# LogUserControl
**Repository Path**: w_liu/log-user-control
## Basic Information
- **Project Name**: LogUserControl
- **Description**: 封装的日志器,记录日志和现实日志
- **Primary Language**: C#
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-08-28
- **Last Updated**: 2026-09-15
## Categories & Tags
**Categories**: Uncategorized
**Tags**: LogUserControl
## README
# LogUserControl 使用说明
一个可发布到 NuGet 的 **WPF User Control Library**,封装了日志记录与日志查看功能。其他项目引用本库后,可以直接使用内置的日志处理器写入日志,并在界面中嵌入日志查看控件实时浏览、按类别切换、按时间/级别查询日志。
---
## 一、功能特性
1. **按类别分文件**:记录日志时传入类别,日志自动写入对应类别的独立文件。
2. **按天滚动**:日志文件按日期命名,每天一个文件,自动归档。
3. **自动清理**:可设置日志保留天数(默认 60 天),过期日志文件自动删除。
4. **类别 Tab 展示**:日志查看控件以 Tab 形式展示所有类别,可切换查看指定类别。
5. **时间 / 级别查询**:支持按开始时间、结束时间、日志级别筛选,并限制显示条数。
6. **现代化外观**:内置现代化主题样式,并支持通过依赖属性定制配色与样式。
7. **开箱即用**:其他项目引用本库后,直接调用 `LogManager` 静态方法即可记录日志。
---
## 二、目录结构
```text
LogUserControl/
├── LogUserControl/ # 主库(WPF User Control Library)
│ ├── Logging/
│ │ ├── LogLevel.cs # 日志级别枚举
│ │ ├── LogEntry.cs # 日志条目模型
│ │ └── LogManager.cs # 核心日志处理器(静态)
│ ├── Controls/
│ │ ├── LogViewerControl.xaml # 日志查看控件(UI)
│ │ ├── LogViewerControl.xaml.cs # 日志查看控件(逻辑)
│ │ └── Themes/ModernStyles.xaml # 内置现代化主题样式
├── Demo/ # 示例项目(可运行的 WPF 应用)
│ ├── App.xaml / App.xaml.cs
│ ├── MainWindow.xaml # 演示写入日志 + 嵌入控件
│ └── MainWindow.xaml.cs
└── LogUserControl.sln
```
---
## 三、环境要求
- .NET SDK(`net10.0-windows`)
- Windows 操作系统(WPF)
- JetBrains Rider 或 Visual Studio 2022+
---
## 四、快速开始(运行 Demo)
在项目根目录执行:
```shell
dotnet run --project Demo\Demo.csproj
```
或在 Rider 中将 `Demo` 设为启动项目后直接运行。
运行后:
- 顶部输入 **类别 / 级别 / 内容**,点击「记录日志」写入一条;
- 点击「随机生成」批量写入 5 条随机日志;
- 下方日志查看控件自动按类别生成 Tab,可切换查看,并支持顶部「开始时间 / 结束时间 / 级别」查询。
日志默认写到 Demo 运行目录下的 `Logs\` 文件夹。
---
## 五、核心概念
### 5.1 命名空间
| 命名空间 | 用途 |
|----------|------|
| `LogUserControl.Logging` | 日志处理器 `LogManager`、`LogLevel`、`LogEntry` |
| `LogUserControl.Controls` | 日志查看控件 `LogViewerControl` |
### 5.2 日志文件结构
```text
Logs/ # 日志根目录(可配置)
├── UserService/
│ ├── 2026-08-28.log
│ └── 2026-08-29.log
├── OrderService/
│ └── 2026-08-28.log
└── System/
│ └── 2026-08-28.log
```
- 每个类别对应一个子目录;
- 每天一个 `.log` 文件,文件名格式 `yyyy-MM-dd.log`;
- 单行日志格式:`[yyyy-MM-dd HH:mm:ss.fff] [LEVEL] message`。
### 5.3 日志级别
`LogLevel` 枚举:`Debug`、`Info`、`Warn`、`Error`、`Fatal`。
---
## 六、详细使用说明
### 6.1 在其他项目中引用本库
**方式一:项目引用(开发阶段)**
在目标项目的 `.csproj` 中添加:
```xml
```
**方式二:NuGet 引用(发布后)**
```shell
dotnet add package LogUserControl
```
---
### 6.2 使用日志处理器 LogManager
`LogManager` 是静态类,所有方法可直接调用,无需实例化。
**引入命名空间:**
```csharp
using LogUserControl.Logging;
```
**(可选)设置日志根目录:**
```csharp
// 不设置则默认写入 程序运行目录\Logs
LogManager.SetLogDirectory(@"D:\MyApp\Logs");
// 或直接读取当前根目录
string dir = LogManager.RootDirectory;
```
**(可选)设置日志保留天数:**
```csharp
// 默认保留 60 天,0 表示永久保留;设置后立即清理过期文件
LogManager.SetRetentionDays(10);
// 或直接赋值
LogManager.RetentionDays = 30;
```
**记录一条日志:**
```csharp
// 基础写法(level 默认为 Info)
LogManager.Log("UserService", "用户登录成功");
// 指定级别
LogManager.Log("OrderService", "订单创建完成", LogLevel.Info);
```
**按级别快捷方法:**
```csharp
LogManager.Debug("UserService", "缓存 key 已刷新");
LogManager.Info("UserService", "用户登录成功");
LogManager.Warn("PaymentService", "支付回调延迟超过 3 秒");
LogManager.Error("OrderService", "库存不足,下单失败");
LogManager.Fatal("System", "数据库连接已断开");
```
**记录异常:**
```csharp
try
{ // 业务逻辑 }
catch (Exception ex)
{
LogManager.LogException("OrderService", ex);
}
```
**读取日志(用于自定义展示):**
```csharp
// 读取指定类别的日志
var logs = LogManager.ReadLogs(
category: "UserService", start: DateTime.Today, // 起始时间(含),可为 null
end: null, // 结束时间(含),可为 null
level: LogLevel.Error, // 级别过滤,可为 null
maxCount: 500
); // 最多返回条数(取最新),可为 null
// 读取所有类别的日志
var allLogs = LogManager.ReadAllLogs(start: null, end: null, level: null, maxCount: 1000);
// 获取当前所有类别
var categories = LogManager.GetCategories();
```
每条日志是一个 `LogEntry`,包含:
| 属性 | 类型 | 说明 |
|------|------|------|
| `Time` | `DateTime` | 记录时间 |
| `Level` | `LogLevel` | 日志级别 |
| `Category` | `string` | 日志类别 |
| `Message` | `string` | 日志内容 |
---
### 6.3 使用日志查看控件 LogViewerControl
**XAML 中声明:**
```xml
```
**依赖属性:**
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `LogDirectory` | `string?` | `null` | 日志根目录;为空时使用 `LogManager` 的默认目录 |
| `AutoRefresh` | `bool` | `true` | 是否自动监听日志目录变化并刷新 |
| `MaxLogCount` | `int` | `0` | 单个类别最多显示的条数,`0` 表示不限 |
| `RetentionDays` | `int` | `60` | 日志文件保留天数,`0` 表示永久保留 |
| `ButtonStyle` | `Style?` | `null` | 顶部按钮样式,为空时使用内置默认样式 |
| `TextBoxStyle` | `Style?` | `null` | 输入框样式,为空时使用内置默认样式 |
| `ComboBoxStyle` | `Style?` | `null` | 下拉框样式,为空时使用内置默认样式 |
| `DatePickerStyle` | `Style?` | `null` | 日期选择器样式,为空时使用内置默认样式 |
| `TabControlStyle` | `Style?` | `null` | 类别 Tab 样式,为空时使用内置默认样式 |
| `PrimaryBrush` | `Brush?` | `null` | 主题主色,为空时使用内置默认主色 |
**XAML 配置示例:**
```xml
```
**代码后置配置:**
```csharp
LogViewer.LogDirectory = @"D:\MyApp\Logs"; // 会自动同步到 LogManager
LogViewer.AutoRefresh = true;
LogViewer.MaxLogCount = 500;
LogViewer.RetentionDays = 10;
```
**手动刷新方法:**
```csharp
LogViewer.RefreshTabs(); // 全量刷新:重建所有类别 Tab 及各 Tab 内容
LogViewer.RefreshCurrent(); // 增量刷新:只刷新当前选中 Tab 的内容(开销更小)
```
> 说明:`AutoRefresh = true` 时,控件通过 `FileSystemWatcher` 自动监听日志目录,日志文件有变化会自动刷新,无需手动调用。
---
### 6.4 定制样式
控件内置了一套现代化主题(靛蓝主色 `#6366F1`)。宿主项目可通过依赖属性覆盖配色与样式。
**改主色:**
```xml
```
**替换按钮 / Tab 样式:**
```xml
```
代码方式:
```csharp
LogViewer.ButtonStyle = (Style)FindResource("MyButtonStyle");
LogViewer.TabControlStyle = (Style)FindResource("MyTabStyle");
```
> 注意:`BasedOn` 里引用的资源键(如 `MyButtonStyle`)必须是已在当前 XAML 资源中定义的真实资源,否则运行时会报「找不到资源」。
---
## 七、完整示例
以下是一个最小可运行的窗口,演示「写入日志 + 展示日志」:
**MainWindow.xaml**
```csharp
using System.IO;
using System.Windows;
using LogUserControl.Logging;
namespace Demo;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var logDir = Path.Combine(AppContext.BaseDirectory, "Logs");
LogViewer.LogDirectory = logDir; // 同时作用于 LogManager
}
private void OnWriteClicked(object sender, RoutedEventArgs e)
{
var category = string.IsNullOrWhiteSpace(CategoryBox.Text) ? "Default" : CategoryBox.Text.Trim();
var message = string.IsNullOrWhiteSpace(MessageBox.Text) ? "测试日志" : MessageBox.Text.Trim();
LogManager.Log(category, message);
LogViewer.RefreshCurrent();
}
}
```
---
## 八、NuGet 打包与发布
主库 `.csproj` 已配置打包元数据(`PackageId`、`Version`、`GeneratePackageOnBuild` 等)。
**打包:**
```shell
cd LogUserControl
dotnet pack -c Release
```
生成文件位于 `LogUserControl\bin\Release\LogUserControl.1.0.0.nupkg`。
**发布到 NuGet:**
```shell
dotnet nuget push bin\Release\LogUserControl.1.0.0.nupkg -k -s https://api.nuget.org/v3/index.json
```
---
## 九、常见问题(FAQ)
**Q1:日志写到哪里了?**
默认写到程序运行目录下的 `Logs\{类别}\yyyy-MM-dd.log`。可通过 `LogManager.SetLogDirectory()` 或控件的 `LogDirectory` 属性修改。
**Q2:为什么切换 Tab 会自动刷新?**
控件默认开启 `AutoRefresh`,通过 `FileSystemWatcher` 监听日志目录。设为 `False` 即可关闭。
**Q3:日志量很大时如何优化?**
设置控件的 `MaxLogCount`(如 `500`),读取时只取最新 N 条,避免一次性加载全部日志。
**Q4:日志内容里的换行会怎样?**
写入时会把换行符 `\r`、`\n` 转成空格,保证每条日志占一行。
**Q5:类别名包含非法字符会怎样?**
非法文件名字符(如 `:`、`*`、`?`)会被替换为下划线 `_`。
**Q6:如何修改控件主题色?**
设置控件的 `PrimaryBrush` 依赖属性即可(如 `LogViewer.PrimaryBrush = new SolidColorBrush(Colors.Red)`),按钮、选中态、下划线指示器会同步变色。
**Q7:如何设置日志保留天数?**
调用 `LogManager.SetRetentionDays(10)` 或设置控件 `RetentionDays = 10`;`0` 表示永久保留,默认 60 天,设置后会自动清理过期文件。