Add XCode skills for entity caching, ORM, and sharding ETL
|
---
name: logging-tracing
description: 使用 NewLife 日志框架和分布å¼é“¾è·¯è¿½è¸ª APM,实现结构化日志ã€å¤šè¾“出和性能追踪
---
# NewLife 日志与链路追踪使用指å—
## 适用场景
- åº”ç”¨ç¨‹åºæ—¥å¿—输出(控制å°ã€æ–‡ä»¶ã€ç½‘络)
- 分布å¼é“¾è·¯è¿½è¸ªå’Œ APM 性能监控
- ä»£ç æ‰§è¡Œæ€§èƒ½è®¡æ—¶
- 与星尘(Stardust)监控平å°é›†æˆ
## 日志系统
### 快速å¯åЍ
```csharp
// å¯ç”¨æŽ§åˆ¶å° + 文件日志
XTrace.UseConsole();
// 输出日志
XTrace.WriteLine("应用å¯åЍ");
XTrace.WriteLine("处ç†ç”¨æˆ· {0} 的请求,耗时 {1}ms", userId, elapsed);
// 输出异常
try { ... }
catch (Exception ex) { XTrace.WriteException(ex); }
// 输出版本信æ¯ï¼ˆåº”用å¯åŠ¨æ—¶è°ƒç”¨ï¼‰
XTrace.WriteVersion();
```
### ILog 接å£
```csharp
public class MyService
{
public ILog Log { get; set; } = Logger.Null;
public void Process()
{
Log.Info("开始处ç†");
Log.Debug("调试信æ¯ï¼šcount={0}", count);
Log.Warn("注æ„:队列积压 {0} æ¡", queue.Count);
Log.Error("处ç†å¤±è´¥ï¼š{0}", ex.Message);
}
}
// 注入日志
var svc = new MyService { Log = XTrace.Log };
```
### 日志级别
| 级别 | 方法 | 场景 |
|------|------|------|
| Debug | `Log.Debug()` | å¼€å‘è°ƒè¯•ä¿¡æ¯ |
| Info | `Log.Info()` | æ£å¸¸ä¸šåŠ¡æµç¨‹ |
| Warn | `Log.Warn()` | 预è¦ä½†ä¸å½±å“è¿è¡Œ |
| Error | `Log.Error()` | 错误需è¦å…³æ³¨ |
| Fatal | `Log.Fatal()` | 致命错误 |
### å¤šç›®æ ‡æ—¥å¿—
```csharp
// ç»„åˆæ—¥å¿—ï¼šåŒæ—¶è¾“出到控制å°å’Œæ–‡ä»¶
var log = new CompositeLog(new ConsoleLog(), new TextFileLog("logs"));
// 文本文件日志
var fileLog = new TextFileLog("logs") { MaxBytes = 10 * 1024 * 1024 }; // 10MB 滚动
// 网络日志
var netLog = new NetworkLog("udp://log-server:514");
```
## 链路追踪(ITracer)
### 基本埋点
```csharp
public class OrderService
{
public ITracer? Tracer { get; set; }
public void CreateOrder(Order order)
{
// 创建追踪 Span(自动计时,自动记录异常)
using var span = Tracer?.NewSpan("CreateOrder", new { order.UserId, order.Amount });
try
{
ValidateOrder(order);
SaveToDb(order);
SendNotification(order);
}
catch (Exception ex)
{
span?.SetError(ex, null); // 记录异常到 Span
throw;
}
}
}
```
### é…置追踪器
```csharp
// 本地追踪器
var tracer = new DefaultTracer
{
Period = 15, // é‡‡æ ·å‘¨æœŸç§’
MaxSamples = 1, // æ£å¸¸é‡‡æ ·æ•°
MaxErrors = 10, // å¼‚å¸¸é‡‡æ ·æ•°
Timeout = 15000, // è¶…æ—¶å¼ºåˆ¶é‡‡æ ·ï¼ˆæ¯«ç§’ï¼‰
Log = XTrace.Log,
};
DefaultTracer.Instance = tracer;
// æ˜Ÿå°˜è¿½è¸ªå™¨ï¼ˆéœ€è¦ Stardust 包)
// var tracer = new StarTracer("http://star.newlifex.com:6600") { ... };
```
### Span 嵌套
```csharp
public async Task ProcessAsync()
{
using var span = Tracer?.NewSpan("Process");
// å Span 自动关è”父 Span
using var span2 = Tracer?.NewSpan("Step1");
await Step1Async();
span2?.Dispose();
using var span3 = Tracer?.NewSpan("Step2", new { key = "value" });
await Step2Async();
}
```
### é™„åŠ æ ‡ç¾
```csharp
using var span = Tracer?.NewSpan("HttpCall");
span?.AppendTag($"url={url}");
span?.AppendTag($"status={response.StatusCode}");
```
## 代ç 计时器
```csharp
// 快速性能测试
var timer = new CodeTimer();
timer.ShowHeader();
timer.Show("å—符串拼接", () =>
{
var s = "";
for (var i = 0; i < 1000; i++) s += i;
});
timer.Show("StringBuilder", () =>
{
var sb = Pool.StringBuilder.Get();
for (var i = 0; i < 1000; i++) sb.Append(i);
sb.Put();
});
```
## 在 NetServer/NetSession ä¸ä½¿ç”¨
```csharp
class MySession : NetSession<MyServer>
{
protected override void OnReceive(ReceivedEventArgs e)
{
// NetSession 内置 Log 和 Tracer
WriteLog("æ”¶åˆ°æ•°æ® {0} å—节", e.Packet?.Total);
using var span = Session?.Tracer?.NewSpan("OnReceive");
// ...
}
}
```
## 注æ„事项
- `Tracer?.NewSpan()` 使用 null æ¡ä»¶è¿ç®—符,未é…置追踪器时零开销
- `using var span = ...` ç¡®ä¿ Span ç»“æŸæ—¶è‡ªåŠ¨ä¸ŠæŠ¥
- `span?.SetError(ex, null)` 在 catch ä¸è°ƒç”¨ï¼Œä¸å½±å“å¼‚å¸¸ä¼ æ’
- çƒç‚¹è·¯å¾„(æ¯ç§’万次以上调用)的 Span å称应固定,ä¸å«å˜é‡
- `XTrace.Log` 是全局日志入å£ï¼Œ`XTrace.UseConsole()` åˆå§‹åŒ–控制å°è¾“出
|