将Feature/XP.Common和Feature/XP.Hardware分支合并至Develop/XP.forHardwareAndCommon,完善XPapp注册和相关硬件类库通用类库功能。

This commit is contained in:
QI Mingxuan
2026-04-16 17:31:13 +08:00
parent 6ec4c3ddaa
commit 2bd6e566c3
581 changed files with 74600 additions and 222 deletions
+177
View File
@@ -0,0 +1,177 @@
# 日志服务使用指南 | Logger Service Usage Guide
## 概述 | Overview
XplorePlane 使用 Serilog 作为底层日志框架,通过 `ILoggerService` 接口提供统一的日志服务。
## 基本用法 | Basic Usage
### 方式 1:自动类型推断(推荐)| Method 1: Auto Type Inference (Recommended)
使用泛型方法 `ForModule<T>()` 自动获取类型的完整名称(命名空间 + 类名):
```csharp
public class PlcService
{
private readonly ILoggerService _logger;
public PlcService(ILoggerService logger)
{
// 自动使用 "XP.Hardware.Plc.Services.PlcService" 作为模块名
// Automatically uses "XP.Hardware.Plc.Services.PlcService" as module name
_logger = logger?.ForModule<PlcService>() ?? throw new ArgumentNullException(nameof(logger));
}
public void DoSomething()
{
_logger.Info("执行操作 | Performing operation");
}
}
```
### 方式 2:手动指定模块名 | Method 2: Manual Module Name
如果需要自定义模块名,可以使用字符串参数:
```csharp
public class PlcService
{
private readonly ILoggerService _logger;
public PlcService(ILoggerService logger)
{
// 手动指定简短的模块名
// Manually specify a short module name
_logger = logger?.ForModule("PlcService") ?? throw new ArgumentNullException(nameof(logger));
}
}
```
### 方式 3:使用 typeof 获取类型名 | Method 3: Using typeof for Type Name
在静态方法或无法使用泛型的场景:
```csharp
public class PlcService
{
private readonly ILoggerService _logger;
public PlcService(ILoggerService logger)
{
// 使用 typeof 获取类型
// Use typeof to get type
_logger = logger?.ForModule<PlcService>() ?? throw new ArgumentNullException(nameof(logger));
}
public static void StaticMethod(ILoggerService logger)
{
// 静态方法中也可以使用泛型
// Can also use generics in static methods
var log = logger.ForModule<PlcService>();
log.Info("静态方法日志 | Static method log");
}
}
```
## 日志级别 | Log Levels
```csharp
// 调试信息(开发环境)| Debug information (development environment)
_logger.Debug("调试信息:变量值={Value} | Debug info: variable value={Value}", someValue);
// 一般信息 | General information
_logger.Info("操作成功 | Operation successful");
// 警告信息 | Warning information
_logger.Warn("连接不稳定 | Connection unstable");
// 错误信息(带异常)| Error information (with exception)
_logger.Error(ex, "操作失败:{Message} | Operation failed: {Message}", ex.Message);
// 致命错误 | Fatal error
_logger.Fatal(ex, "系统崩溃 | System crash");
```
## 日志输出格式 | Log Output Format
使用 `ForModule<T>()` 后,日志会自动包含完整的类型信息:
```
2026-03-12 10:30:15.123 [INF] [XP.Hardware.Plc.Services.PlcService] 正在初始化 PLC 连接... | Initializing PLC connection...
2026-03-12 10:30:16.456 [INF] [XP.Hardware.Plc.Services.PlcService] PLC 连接成功 | PLC connection successful
```
## 最佳实践 | Best Practices
### 1. 在构造函数中初始化日志器 | Initialize Logger in Constructor
```csharp
public class MyService
{
private readonly ILoggerService _logger;
public MyService(ILoggerService logger)
{
_logger = logger?.ForModule<MyService>() ?? throw new ArgumentNullException(nameof(logger));
}
}
```
### 2. 使用结构化日志 | Use Structured Logging
```csharp
// 好的做法:使用占位符 | Good: use placeholders
_logger.Info("用户 {UserId} 执行了操作 {Action} | User {UserId} performed action {Action}", userId, action);
// 不好的做法:字符串拼接 | Bad: string concatenation
_logger.Info($"用户 {userId} 执行了操作 {action}");
```
### 3. 异常日志包含上下文 | Exception Logs Include Context
```csharp
try
{
await _plcClient.ConnectAsync(config);
}
catch (PlcException ex)
{
_logger.Error(ex, "PLC 连接失败:地址={Address}, 端口={Port} | PLC connection failed: address={Address}, port={Port}",
config.Address, config.Port);
throw;
}
```
## 对比:三种方式的输出 | Comparison: Output of Three Methods
```csharp
// 方式 1ForModule<T>() - 完整类型名
// Method 1: ForModule<T>() - Full type name
_logger = logger.ForModule<PlcService>();
// 输出 | Output: [XP.Hardware.Plc.Services.PlcService]
// 方式 2ForModule("PlcService") - 自定义名称
// Method 2: ForModule("PlcService") - Custom name
_logger = logger.ForModule("PlcService");
// 输出 | Output: [PlcService]
// 方式 3:不调用 ForModule - 无模块标记
// Method 3: Don't call ForModule - No module tag
_logger = logger;
// 输出 | Output: [] (空标记 | empty tag)
```
## 配置 | Configuration
日志配置在 `App.config` 中设置,通过 `SerilogConfig` 加载:
```xml
<appSettings>
<add key="Serilog:LogPath" value="C:\Logs\XplorePlane" />
<add key="Serilog:MinimumLevel" value="Information" />
<add key="Serilog:EnableConsole" value="true" />
<add key="Serilog:RollingInterval" value="Day" />
<add key="Serilog:FileSizeLimitMB" value="100" />
<add key="Serilog:RetainedFileCountLimit" value="30" />
</appSettings>
```