解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
大石头 authored at 2018-05-15 21:21:05
14.58 KiB
X
# Á´Â·×·×Ù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**: ³õʼ°æ±¾·¢²¼