解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
|
# Á´Â·×·×ÙITracer
## ¸ÅÊö
¿É¹Û²âÐÔÊǺâÁ¿ÏÖ´úÓ¦ÓÃÖÊÁ¿µÄºËÐÄÖ¸±êÖ®Ò»¡£NewLife.Core ÌṩÁËÒ»Ì×ÍêÕûµÄÁ´Â·×·×ٹ淶£º`ITracer`/`ISpan`£¬ÓÃÓÚʵÏÖÇáÁ¿¼¶ APM£¨Application Performance Monitoring£©¡£
Ó봫ͳ APM ϵͳ²»Í¬£¬NewLife µÄÁ´Â·×·×Ù²ÉÓÃ**±¾µØ²ÉÑù+ͳ¼Æ**µÄ·½Ê½£º
- ÔÚ±¾µØÍê³ÉÊý¾Ý²ÉÑùºÍ³õ²½Í³¼Æ
- ½öÉϱ¨Í³¼ÆÊý¾ÝºÍÉÙÁ¿²ÉÑùÑù±¾
- ¼«´ó½ÚÊ¡ÍøÂç´«ÊäºÍ´æ´¢³É±¾
NewLife ȫϵÁÐÏîÄ¿£¨30+ ×é¼þ£©¾ùÄÚÖÃÁË `ITracer` Âñµã£¬¿ª·¢Õß¿ÉÒÔ£º
1. ÎÞÇÖÈëµØ»ñÈ¡×é¼þÔËÐÐÖ¸±ê
2. ½ÓÈëÐdz¾¼à¿ØÆ½Ì¨ÊµÏÖ·Ö²¼Ê½×·×Ù
3. »ùÓڹ淶À©Õ¹×Ô¶¨ÒåÂñµã
**Nuget °ü**: `NewLife.Core`
**Ô´Âë**: [NewLife.Core/Log/ITracer.cs](https://github.com/NewLifeX/X/blob/master/NewLife.Core/Log/ITracer.cs)
---
## ¿ìËÙÈëÃÅ
### »ù´¡Ó÷¨
×î¼òµ¥µÄÂñµãʾÀý£º
```csharp
using var span = tracer?.NewSpan("²Ù×÷Ãû³Æ");
```
ʹÓà `using` ¹Ø¼ü×ÖÈ·±£ span ÔÚ×÷ÓÃÓò½áÊøÊ±×Ô¶¯Íê³É£¬¼Ç¼ºÄʱºÍ´ÎÊý¡£
### ÍêÕûʾÀý
ÒÔÏÂÊÇÍøÂç½ÓÊÕÊý¾ÝµÄÂñµãʾÀý£º
```csharp
private void Ss_Received(Object? sender, ReceivedEventArgs e)
{
var ns = (this as INetSession).Host;
var tracer = ns?.Tracer;
// ´´½¨Âñµã£¬¼Ç¼½ÓÊÕ²Ù×÷
using var span = tracer?.NewSpan($"net:{ns?.Name}:Receive", e.Message);
try
{
OnReceive(e);
}
catch (Exception ex)
{
// ±ê¼Ç´íÎ󲢼ǼÒì³£ÐÅÏ¢
span?.SetError(ex, e.Message ?? e.Packet);
throw;
}
}
```
Õâ¸öʾÀýÑÝʾÁË£º
- **´´½¨Âñµã**£ºÊ¹Óö¯Ì¬Éú³ÉµÄÃû³Æ
- **Êý¾Ý±êÇ©**£ºµÚ¶þ¸ö²ÎÊý `e.Message` ×÷ΪÊý¾Ý±êÇ©
- **Òì³£´¦Àí**£ºÍ¨¹ý `SetError` ±ê¼ÇÒì³£Âñµã
- **×Ô¶¯¼Ç¼**£º`using` Óï¾ä×Ô¶¯¼Ç¼ºÄʱ
ͨ¹ýÕâ¸öÂñµã£¬ÎÒÃÇ¿ÉÒÔ£º
- ͳ¼Æ½ÓÊÕÊý¾Ý°üµÄ´ÎÊý
- ¼Ç¼ÿ´Î½ÓÊյĺÄʱ
- ͳ¼ÆÒì³£·¢Éú´ÎÊý
- ²é¿´²ÉÑùÊý¾ÝºÍ±êÇ©
---
## ºËÐĽӿÚ
### ITracer ½Ó¿Ú
ÐÔÄܸú×ÙÆ÷£¬ÇáÁ¿¼¶ APM ¹æ·¶µÄºËÐĽӿڡ£
```csharp
public interface ITracer
{
#region ÊôÐÔ
/// <summary>²ÉÑùÖÜÆÚ¡£µ¥Î»Ã룬ĬÈÏ15Ãë</summary>
Int32 Period { get; set; }
/// <summary>×î´óÕý³£²ÉÑùÊý¡£²ÉÑùÖÜÆÚÄÚ£¬×î¶àÖ»¼Ç¼ָ¶¨ÊýÁ¿µÄÕý³£Ê¼þ£¬Ä¬ÈÏ1</summary>
Int32 MaxSamples { get; set; }
/// <summary>×î´óÒì³£²ÉÑùÊý¡£²ÉÑùÖÜÆÚÄÚ£¬×î¶àÖ»¼Ç¼ָ¶¨ÊýÁ¿µÄÒ쳣ʼþ£¬Ä¬ÈÏ10</summary>
Int32 MaxErrors { get; set; }
/// <summary>³¬Ê±Ê±¼ä¡£³¬¹ý¸Ãʱ¼äÊ±Ç¿ÖÆ²ÉÑù£¬µ¥Î»ºÁÃ룬ĬÈÏ5000</summary>
Int32 Timeout { get; set; }
/// <summary>×î´ó±êÇ©³¤¶È¡£³¬¹ý¸Ã³¤¶Èʱ½«½Ø¶Ï£¬Ä¬ÈÏ1024×Ö·û</summary>
Int32 MaxTagLength { get; set; }
/// <summary>Ïòhttp/rpcÇëÇó×¢ÈëTraceIdµÄ²ÎÊýÃû£¬Îª¿Õ±íʾ²»×¢È룬ĬÈÏW3C±ê×¼µÄtraceparent</summary>
String? AttachParameter { get; set; }
#endregion
/// <summary>½¨Á¢Span¹¹½¨Æ÷</summary>
/// <param name="name">²Ù×÷Ãû³Æ£¬ÓÃÓÚ±êʶ²»Í¬µÄÂñµãÀàÐÍ</param>
ISpanBuilder BuildSpan(String name);
/// <summary>¿ªÊ¼Ò»¸öSpan</summary>
/// <param name="name">²Ù×÷Ãû³Æ£¬ÓÃÓÚ±êʶ²»Í¬µÄÂñµãÀàÐÍ</param>
ISpan NewSpan(String name);
/// <summary>¿ªÊ¼Ò»¸öSpan£¬Ö¸¶¨Êý¾Ý±êÇ©</summary>
/// <param name="name">²Ù×÷Ãû³Æ£¬ÓÃÓÚ±êʶ²»Í¬µÄÂñµãÀàÐÍ</param>
/// <param name="tag">Êý¾Ý±êÇ©£¬¼Ç¼¹Ø¼ü²ÎÊýÐÅÏ¢</param>
ISpan NewSpan(String name, Object? tag);
/// <summary>½Ø¶ÏËùÓÐSpan¹¹½¨Æ÷Êý¾Ý£¬ÖØÖü¯ºÏ</summary>
ISpanBuilder[] TakeAll();
}
```
#### ¹Ø¼üÊôÐÔ˵Ã÷
| ÊôÐÔ | ĬÈÏÖµ | ˵Ã÷ |
|-----|-------|------|
| `Period` | 15Ãë | ²ÉÑùÖÜÆÚ£¬¶¨ÆÚÉϱ¨Êý¾ÝµÄʱ¼ä¼ä¸ô |
| `MaxSamples` | 1 | ÿ¸öÖÜÆÚÄڼǼµÄÕý³£²ÉÑùÊý£¬ÓÃÓÚ»æÖƵ÷ÓÃÒÀÀµ¹ØÏµ |
| `MaxErrors` | 10 | ÿ¸öÖÜÆÚÄڼǼµÄÒì³£²ÉÑùÊý£¬ÓÃÓÚÎÊÌâÕï¶Ï |
| `Timeout` | 5000ms | ³¬Ê±ãÐÖµ£¬³¬¹ý´Ëʱ¼äµÄ²Ù×÷»á±»Ç¿ÖƲÉÑù |
| `MaxTagLength` | 1024 | ±êÇ©×î´ó³¤¶È£¬³¬¹ý»á±»½Ø¶Ï |
| `AttachParameter` | "traceparent" | HTTP/RPC ÇëÇóÖÐ×¢Èë TraceId µÄ²ÎÊýÃû£¬×ñÑ W3C ±ê×¼ |
ÕâЩ²ÎÊýͨ³£ÓÉÐdz¾¼à¿ØÖÐÐĶ¯Ì¬Ï·¢µ÷Õû£¬ÎÞÐèÊÖ¶¯ÅäÖá£
#### ºËÐÄ·½·¨
- **`NewSpan(String name)`**: ×î³£Óõķ½·¨£¬´´½¨Ò»¸öÐÂÂñµã
- **`NewSpan(String name, Object? tag)`**: ´´½¨Âñµã²¢¸½¼ÓÊý¾Ý±êÇ©
- **`BuildSpan(String name)`**: »ñÈ¡»ò´´½¨ SpanBuilder£¬ÓÃÓڸ߼¶³¡¾°
### ISpan ½Ó¿Ú
ÐÔÄܸú×ÙÆ¬¶Î£¬´ú±íÒ»¸ö¾ßÌåµÄÂñµãʵÀý¡£
```csharp
public interface ISpan : IDisposable
{
/// <summary>Ψһ±êʶ¡£ËæÏß³ÌÉÏÏÂÎÄ¡¢Http¡¢Rpc´«µÝ£¬×÷ΪÄÚ²¿Æ¬¶ÎµÄ¸¸¼¶</summary>
String Id { get; set; }
/// <summary>ÂñµãÃû¡£ÓÃÓÚ±êʶ²»Í¬ÀàÐ͵IJÙ×÷</summary>
String Name { get; set; }
/// <summary>¸¸¼¶Æ¬¶Î±êʶ¡£ÓÃÓÚ¹¹½¨µ÷ÓÃÁ´</summary>
String? ParentId { get; set; }
/// <summary>¸ú×Ù±êʶ¡£¿ÉÓÃÓÚ¹ØÁª¶à¸öƬ¶Î£¬½¨Á¢ÒÀÀµ¹ØÏµ£¬ËæÏß³ÌÉÏÏÂÎÄ¡¢Http¡¢Rpc´«µÝ</summary>
String TraceId { get; set; }
/// <summary>¿ªÊ¼Ê±¼ä¡£UnixºÁÃëʱ¼ä´Á</summary>
Int64 StartTime { get; set; }
/// <summary>½áÊøÊ±¼ä¡£UnixºÁÃëʱ¼ä´Á</summary>
Int64 EndTime { get; set; }
/// <summary>Óû§ÊýÖµ¡£¼Ç¼Êý×ÖÐͱêÁ¿£¬Èçÿ´ÎÊý¾Ý¿â²Ù×÷ÐÐÊý£¬Ðdz¾Æ½Ì¨»ã×Üͳ¼Æ</summary>
Int64 Value { get; set; }
/// <summary>Êý¾Ý±êÇ©¡£¼Ç¼һЩ¸½¼ÓÊý¾Ý£¬ÈçÇëÇó²ÎÊý¡¢ÏìÓ¦½á¹ûµÈ</summary>
String? Tag { get; set; }
/// <summary>´íÎóÐÅÏ¢¡£¼Ç¼Òì³£ÏûÏ¢</summary>
String? Error { get; set; }
/// <summary>ÉèÖôíÎóÐÅÏ¢£¬ApiException³ýÍâ</summary>
void SetError(Exception ex, Object? tag = null);
/// <summary>ÉèÖÃÊý¾Ý±êÇ©¡£ÄÚ²¿¸ù¾Ý×î´ó³¤¶È½Ø¶Ï</summary>
void SetTag(Object tag);
/// <summary>ÅׯúÂñµã£¬²»¼ÆÈë²É¼¯</summary>
void Abandon();
}
```
#### ¹Ø¼üÊôÐÔ
| ÊôÐÔ | ÀàÐÍ | ˵Ã÷ |
|-----|------|------|
| `Id` | String | Span Ψһ±êʶ£¬×ñÑ W3C ±ê×¼ |
| `ParentId` | String? | ¸¸¼¶ Span ID£¬ÓÃÓÚ¹¹½¨µ÷ÓÃÊ÷ |
| `TraceId` | String | ¸ú×ÙÁ´±êʶ£¬Í¬Ò»µ÷ÓÃÁ´ÖеÄËùÓÐ Span ¹²ÏíÏàͬ TraceId |
| `StartTime` | Int64 | ¿ªÊ¼Ê±¼ä£¨Unix ºÁÃ룩 |
| `EndTime` | Int64 | ½áÊøÊ±¼ä£¨Unix ºÁÃ룩 |
| `Value` | Int64 | Óû§ÊýÖµ£¬¿É¼Ç¼ҵÎñÖ¸±ê£¨ÈçÊý¾Ý¿âÐÐÊý£© |
| `Tag` | String? | Êý¾Ý±êÇ©£¬¼Ç¼ÇëÇó²ÎÊý¡¢ÏìÓ¦Êý¾ÝµÈ |
| `Error` | String? | ´íÎóÐÅÏ¢ |
#### ºËÐÄ·½·¨
- **`SetError(Exception ex, Object? tag)`**: ±ê¼ÇÒì³££¬`ApiException` ÀàÐÍ»á±»ÌØÊâ´¦Àí
- **`SetTag(Object tag)`**: ÉèÖÃÊý¾Ý±êÇ©£¬Ö§³Ö¶àÖÖÀàÐÍ×Ô¶¯ÐòÁл¯
- **`Abandon()`**: ¶ªÆúµ±Ç°Âñµã£¬³£ÓÃÓÚ¹ýÂËÎÞЧÇëÇó£¨Èç404ɨÃ裩
---
## ʹÓÃ×î¼Ñʵ¼ù
### 1. ×¢Èë ITracer
ÔÚ ASP.NET Core Ó¦ÓÃÖУ¬Í¨¹ýÐdz¾À©Õ¹×¢È룺
```csharp
using NewLife.Stardust.Extensions;
var builder = WebApplication.CreateBuilder(args);
// ×¢ÈëÐdz¾£¬°üº¬ ITracer ʵÏÖ
builder.Services.AddStardust();
```
Ïê¼û£º[Ðdz¾·Ö²¼Ê½·þÎñƽ̨](https://newlifex.com/blood/stardust)
### 2. »ñÈ¡ ITracer ʵÀý
ÓжàÖÖ·½Ê½»ñÈ¡ `ITracer`£º
```csharp
// ·½Ê½1£º¹¹Ô캯Êý×¢Èë£¨ÍÆ¼ö£©
public class MyService
{
private readonly ITracer _tracer;
public MyService(ITracer tracer)
{
_tracer = tracer;
}
}
// ·½Ê½2£ºÊôÐÔ×¢Èë
public class MyService
{
public ITracer? Tracer { get; set; }
}
// ·½Ê½3£ºÊ¹ÓÃÈ«¾Ö¾²Ì¬ÊµÀý
var tracer = DefaultTracer.Instance;
```
### 3. ´´½¨Âñµã
#### »ù´¡Âñµã
```csharp
using var span = _tracer?.NewSpan("MyOperation");
// ÒµÎñÂß¼
```
#### ´øÊý¾Ý±êÇ©µÄÂñµã
```csharp
var request = new { UserId = 123, Action = "Query" };
using var span = _tracer?.NewSpan("UserQuery", request);
// ÒµÎñÂß¼
```
#### ´øÒì³£´¦ÀíµÄÂñµã
```csharp
using var span = _tracer?.NewSpan("DatabaseQuery");
try
{
// Ö´ÐÐÊý¾Ý¿â²éѯ
var result = await ExecuteQueryAsync();
}
catch (Exception ex)
{
span?.SetError(ex, "²éѯʧ°Ü");
throw;
}
```
#### ¼Ç¼ҵÎñÖ¸±ê
```csharp
using var span = _tracer?.NewSpan("BatchProcess");
var count = ProcessRecords();
span.Value = count; // ¼Ç¼´¦ÀíµÄ¼Ç¼Êý
```
### 4. ¶¨Ê±ÈÎÎñÂñµãʾÀý
```csharp
public class DataRetentionService : IHostedService
{
private readonly ITracer _tracer;
private readonly StarServerSetting _setting;
private TimerX? _timer;
public DataRetentionService(StarServerSetting setting, ITracer tracer)
{
_setting = setting;
_tracer = tracer;
}
public Task StartAsync(CancellationToken cancellationToken)
{
// ÿ600ÃëÖ´ÐÐÒ»´Î£¬Ëæ»úÑÓ³ÙÆô¶¯
_timer = new TimerX(DoWork, null,
DateTime.Today.AddMinutes(Rand.Next(60)),
600 * 1000)
{
Async = true
};
return Task.CompletedTask;
}
private void DoWork(Object? state)
{
var set = _setting;
if (set.DataRetention <= 0) return;
var time = DateTime.Now.AddDays(-set.DataRetention);
var time2 = DateTime.Now.AddDays(-set.DataRetention2);
var time3 = DateTime.Now.AddDays(-set.DataRetention3);
// ´´½¨Âñµã£¬¼Ç¼ÇåÀíÈÎÎñ
using var span = _tracer?.NewSpan("DataRetention", new { time, time2, time3 });
try
{
// ɾ³ý¾ÉÊý¾Ý
var rs = AppMinuteStat.DeleteBefore(time);
XTrace.WriteLine("ɾ³ý[{0}]֮ǰµÄAppMinuteStat¹²£º{1:n0}", time, rs);
rs = TraceMinuteStat.DeleteBefore(time);
XTrace.WriteLine("ɾ³ý[{0}]֮ǰµÄTraceMinuteStat¹²£º{1:n0}", time, rs);
}
catch (Exception ex)
{
span?.SetError(ex, null);
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
_timer?.TryDispose();
return Task.CompletedTask;
}
}
```
### 5. ¹ýÂËÎÞЧÇëÇó
ÔÚ Web Ó¦ÓÃÖУ¬¾³£Óöµ½¸÷ÖÖɨÃèÇëÇ󣬿ÉÒÔʹÓà `Abandon()` ¶ªÆúÕâЩÂñµã£º
```csharp
public IActionResult ProcessRequest()
{
using var span = _tracer?.NewSpan("WebRequest");
// ¼ì²âµ½ÎÞЧÇëÇó£¨Èç404ɨÃ裩
if (IsInvalidScan())
{
span?.Abandon(); // ¶ªÆúÂñµã£¬²»¼ÆÈëͳ¼Æ
return NotFound();
}
// Õý³£´¦Àí
return Ok();
}
```
---
## ·Ö²¼Ê½Á´Â·×·×Ù
### ¿ç·þÎñ´«µÝ
ISpan ÌṩÁËÀ©Õ¹·½·¨£¬Ö§³Öͨ¹ý HTTP/RPC ´«µÝ¸ú×ÙÉÏÏÂÎÄ£º
```csharp
// HTTP ÇëÇó×¢Èë
var request = new HttpRequestMessage(HttpMethod.Get, url);
span?.Attach(request); // ×¢Èë traceparent Í·
await httpClient.SendAsync(request);
// RPC µ÷ÓÃ×¢Èë
var args = new { UserId = 123 };
span?.Attach(args); // ×¢Èë¸ú×Ù²ÎÊý
await rpcClient.InvokeAsync("Method", args);
```
·þÎñ¶ËÊÕµ½ÇëÇóºó£¬»á×Ô¶¯½âÎö `traceparent` ²ÎÊý£¬»Ö¸´¸ú×ÙÉÏÏÂÎÄ¡£
### µ÷ÓÃÁ´¹¹½¨
ͬһ¸ö `TraceId` ϵÄËùÓÐ Span »á×Ô¶¯Ðγɵ÷ÓÃÁ´£º
```
TraceId: ac1b1e8617342790000015eb0ea2a6
©À©¤ DataRetention (¸¸)
©À©¤ SQL:AppMinuteStat.DeleteBefore (×Ó)
©À©¤ SQL:TraceMinuteStat.DeleteBefore (×Ó)
©¸©¤ SQL:TraceHourStat.DeleteBefore (×Ó)
```
ÔÚÐdz¾¼à¿ØÆ½Ì¨¿ÉÒԲ鿴£º
- [µ÷ÓÃÁ´»ðÑæÍ¼](https://star.newlifex.com/trace?id=ac1b1e8617342790000015eb0ea2a6)
- [µ÷ÓÃÁ´ÈÕÖ¾ÊÓͼ](https://star.newlifex.com/trace?id=ac1b1e8617342790000015eb0ea2a6&layout=detail)
---
## ¼à¿ØÓë·ÖÎö
### ²é¿´Í³¼ÆÊý¾Ý
ÔÚÐdz¾¼à¿ØÆ½Ì¨¿ÉÒԲ鿴Âñµãͳ¼Æ£º
- µ÷ÓÃ×Ü´ÎÊý
- Òì³£´ÎÊý
- ƽ¾ùºÄʱ¡¢×î´óºÄʱ¡¢×îСºÄʱ
- QPS£¨Ã¿ÃëÇëÇóÊý£©
ʾÀý£º[DataRetention Âñµãͳ¼Æ](https://star.newlifex.com/Monitors/traceDayStat?appId=4&itemId=284)
### ²ÉÑù²ßÂÔ
ITracer ²ÉÓÃÖÇÄܲÉÑù²ßÂÔ£º
1. **Õý³£²ÉÑù**£ºÃ¿¸öÖÜÆÚÄÚ×î¶à±£Áô `MaxSamples` ¸öÕý³£Ñù±¾£¨Ä¬ÈÏ1¸ö£©
2. **Òì³£²ÉÑù**£ºÃ¿¸öÖÜÆÚÄÚ×î¶à±£Áô `MaxErrors` ¸öÒì³£Ñù±¾£¨Ä¬ÈÏ10¸ö£©
3. **³¬Ê±²ÉÑù**£ººÄʱ³¬¹ý `Timeout` µÄ²Ù×÷Ç¿ÖÆ²ÉÑù
4. **È«Á´Â·²ÉÑù**£ºÉèÖà `TraceFlag` µÄµ÷ÓÃÁ´È«Á¿²ÉÑù
### ±¾µØÍ³¼Æ»úÖÆ
ÿ¸öÂñµãÃû¶ÔÓ¦Ò»¸ö `SpanBuilder`£¬ÓÃÓÚÀÛ¼Óͳ¼Æ£º
- **Total**: ×Ü´ÎÊý
- **Errors**: Òì³£´ÎÊý
- **Cost**: ×ܺÄʱ
- **MaxCost**: ×î´óºÄʱ
- **MinCost**: ×îСºÄʱ
ÿ¸ö²ÉÑùÖÜÆÚ½áÊøºó£¬`SpanBuilder` Êý¾Ý´ò°üÉϱ¨£¬È»ºóÖØÖüÆÊýÆ÷¡£
---
## ¸ß¼¶ÌØÐÔ
### ÂñµãÃüÃû¹æ·¶
½¨ÒéʹÓ÷ֲãÃüÃû£¬±ãÓÚ·ÖÀàͳ¼Æ£º
```csharp
// ÍøÂç²ã
tracer.NewSpan("net:{ÐÒé}:Receive");
tracer.NewSpan("net:tcp:Send");
// Êý¾Ý¿â²ã
tracer.NewSpan("db:{±íÃû}:Select");
tracer.NewSpan("db:User:Insert");
// ÒµÎñ²ã
tracer.NewSpan("biz:{Ä£¿é}:{²Ù×÷}");
tracer.NewSpan("biz:Order:Create");
// Íⲿµ÷ÓÃ
tracer.NewSpan("http:{·þÎñ}:{·½·¨}");
tracer.NewSpan("http:PaymentApi:Pay");
```
### ¶¯Ì¬²ÎÊýµ÷Õû
¿ÉÒÔ¶¯Ì¬µ÷Õû²ÉÑù²ÎÊý£º
```csharp
var tracer = DefaultTracer.Instance;
tracer.Period = 30; // ¸ÄΪ30ÃëÖÜÆÚ
tracer.MaxSamples = 5; // Ôö¼ÓÕý³£²ÉÑùÊý
tracer.Timeout = 10000; // ³¬Ê±ãÐÖµ¸ÄΪ10Ãë
tracer.MaxTagLength = 2048; // ±êÇ©³¤¶È¸ÄΪ2K
```
ͨ³£ÕâЩ²ÎÊýÓÉÐdz¾¼à¿ØÖÐÐÄͳһÏ·¢¡£
### ×Ô¶¨Òå ITracer ʵÏÖ
¿ÉÒÔʵÏÖ×Ô¼ºµÄ `ITracer`£º
```csharp
public class CustomTracer : ITracer
{
public Int32 Period { get; set; } = 15;
public Int32 MaxSamples { get; set; } = 1;
public Int32 MaxErrors { get; set; } = 10;
// ... ʵÏÖ½Ó¿Ú·½·¨
public ISpan NewSpan(String name)
{
// ×Ô¶¨ÒåÂñµã´´½¨Âß¼
var span = new CustomSpan { Name = name };
span.Start();
return span;
}
}
// ×¢²á×Ô¶¨ÒåʵÏÖ
DefaultTracer.Instance = new CustomTracer();
```
---
## ÐÔÄÜÓÅ»¯
### ¶ÔÏó³Ø
`DefaultTracer` ÄÚÖÃÁ˶ÔÏ󳨣¬¸´Óà `ISpanBuilder` ºÍ `ISpan` ʵÀý£º
```csharp
public IPool<ISpanBuilder> BuilderPool { get; }
public IPool<ISpan> SpanPool { get; }
```
Ƶ·±´´½¨µÄÂñµã¶ÔÏó»á×Ô¶¯¹é»¹¶ÔÏ󳨣¬¼õÉÙ GC ѹÁ¦¡£
### ±êÇ©³¤¶È¿ØÖÆ
¶ÔÓÚ´óÐͶÔÏ󣬽¨Òé¿ØÖÆ±êÇ©ÄÚÈÝ£º
```csharp
// ²»ÍƼö£º¼Ç¼Õû¸ö´ó¶ÔÏó
span.SetTag(largeObject);
// ÍÆ¼ö£ºÖ»¼Ç¼¹Ø¼üÐÅÏ¢
span.SetTag(new { Id = obj.Id, Name = obj.Name });
```
### Ìõ¼þÂñµã
¶ÔÓڷǹؼü·¾¶£¬¿ÉÒÔÌõ¼þÐÔ´´½¨Âñµã£º
```csharp
ISpan? span = null;
if (_tracer != null && IsImportantOperation())
{
span = _tracer.NewSpan("ImportantOp");
}
try
{
// ÒµÎñÂß¼
}
finally
{
span?.Dispose();
}
```
---
## Òì³£´¦Àí
### ApiException ÌØÊâ´¦Àí
ÒµÎñÒì³£ `ApiException` ²»»á±»±ê¼ÇΪ´íÎó£º
```csharp
catch (ApiException aex)
{
span?.SetError(aex, request);
// ¼Ç¼ΪÕý³£Âñµã£¬TagÖаüº¬ÒµÎñ´íÎóÂë
}
catch (Exception ex)
{
span?.SetError(ex, request);
// ¼Ç¼ΪÒì³£Âñµã£¬ErrorÖаüº¬Òì³£ÏûÏ¢
}
```
### Òì³£Âñµã
ÿ¸öÒì³£»á×Ô¶¯´´½¨¶ÀÁ¢µÄÒì³£Âñµã£¬±ãÓÚ°´Òì³£ÀàÐÍͳ¼Æ£º
```csharp
// ÔʼÂñµã
using var span = tracer.NewSpan("DatabaseQuery");
try
{
// Å׳öÒì³£
throw new TimeoutException("²éѯ³¬Ê±");
}
catch (Exception ex)
{
span.SetError(ex, query);
// ×Ô¶¯´´½¨ "ex:TimeoutException" Âñµã
}
```
---
## ³£¼ûÎÊÌâ
### 1. ÂñµãÊý¾ÝÔÚÐdz¾Æ½Ì¨¿´²»µ½£¿
¼ì²éÒÔϼ¸µã£º
- È·ÈÏÒÑ×¢ÈëÐdz¾À©Õ¹£º`services.AddStardust()`
- ¼ì²éÍøÂçÁ¬½Óµ½Ðdz¾·þÎñÆ÷
- ¼ì²éÓ¦ÓÃÔÚÐdz¾Æ½Ì¨ÊÇ·ñÒÑ×¢²á
- ²é¿´±¾µØÈÕÖ¾£¬È·ÈÏÂñµãÕý³£´´½¨
### 2. ²ÉÑùÊý¾ÝÌ«ÉÙ£¿
µ÷Õû²ÉÑù²ÎÊý£º
```csharp
tracer.MaxSamples = 10; // Ôö¼ÓÕý³£²ÉÑùÊý
tracer.MaxErrors = 50; // Ôö¼ÓÒì³£²ÉÑùÊý
tracer.Timeout = 1000; // ½µµÍ³¬Ê±ãÐÖµ
```
### 3. ÈçºÎ¹Ø±ÕÂñµã£¿
```csharp
// ·½Ê½1£º²»×¢Èë ITracer
// services.AddStardust(); // ×¢Ê͵ô
// ·½Ê½2£ºÊ¹ÓÿÕʵÏÖ
DefaultTracer.Instance = null;
```
### 4. ÈçºÎ²é¿´±¾µØÂñµãÊý¾Ý£¿
DefaultTracer »áÊä³öµ½ÈÕÖ¾£º
```
Tracer[DataRetention] Total=10 Errors=0 Speed=0.02tps Cost=1500ms MaxCost=2000ms MinCost=1000ms
```
### 5. ²¢·¢³¡¾°Ï Span »áÂÒÂð£¿
²»»á¡£`ISpan` ʹÓà `AsyncLocal<ISpan>` ±£´æÉÏÏÂÎÄ£¬Ã¿¸öÒì²½Á÷³Ì¶ÀÁ¢£º
```csharp
public static AsyncLocal<ISpan?> Current { get; }
```
---
## ²Î¿¼×ÊÁÏ
- **Ðdz¾¼à¿ØÆ½Ì¨**: https://newlifex.com/blood/stardust
- **W3C Trace Context**: https://www.w3.org/TR/trace-context/
- **Ô´Âë²Ö¿â**: https://github.com/NewLifeX/X
- **ÔÚÏßÎĵµ**: https://newlifex.com/core/tracer
---
## ¸üÐÂÈÕÖ¾
- **2024-12-16**: ÍêÉÆÎĵµ£¬²¹³ä×î¼Ñʵ¼ùºÍʾÀý´úÂë
- **2024-08**: Ö§³Ö .NET 9.0
- **2023-11**: Ôö¼Ó `Abandon()` ·½·¨
- **2023-06**: ÓÅ»¯¶ÔÏ󳨣¬ÌáÉýÐÔÄÜ
- **2022**: ³õʼ°æ±¾·¢²¼
|