diff --git a/NewLife.Core/Log/ISpan.cs b/NewLife.Core/Log/ISpan.cs
index 31e6abb3f..c360138fb 100644
--- a/NewLife.Core/Log/ISpan.cs
+++ b/NewLife.Core/Log/ISpan.cs
@@ -22,6 +22,9 @@ public interface ISpan : IDisposable
/// 唯一标识。随线程上下文、Http、Rpc传递,作为内部片段的父级
String Id { get; set; }
+ /// 埋点名
+ String Name { get; set; }
+
/// 父级片段标识
String? ParentId { get; set; }
@@ -64,13 +67,22 @@ public interface ISpan : IDisposable
public class DefaultSpan : ISpan
{
#region 属性
+ /// 跟踪器
+ [XmlIgnore, ScriptIgnore, IgnoreDataMember]
+ public ITracer? Tracer { get; set; }
+
/// 构建器
+ [Obsolete]
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
public ISpanBuilder? Builder { get; set; }
/// 唯一标识。随线程上下文、Http、Rpc传递,作为内部片段的父级
public String Id { get; set; } = null!;
+ /// 埋点名
+ [XmlIgnore, ScriptIgnore, IgnoreDataMember]
+ public String Name { get; set; } = null!;
+
/// 父级片段标识
public String? ParentId { get; set; }
@@ -115,8 +127,8 @@ public class DefaultSpan : ISpan
public DefaultSpan() { }
/// 实例化
- ///
- public DefaultSpan(ISpanBuilder builder) => Builder = builder;
+ ///
+ public DefaultSpan(ITracer tracer) => Tracer = tracer;
static DefaultSpan()
{
@@ -214,20 +226,22 @@ protected virtual void Finish()
// 从本线程中清除跟踪标识
Current = _parent;
- var builder = Builder;
- if (builder == null) return;
+ var tracer = Tracer;
+ if (tracer == null) return;
- var name = builder.Name;
+ var name = Name;
if (!name.IsNullOrEmpty())
{
- // Builder这一批可能已经上传,重新取一次,以防万一
- builder = builder.Tracer?.BuildSpan(name);
+ //!!! Builder这一批可能已经上传,重新取一次,以防万一。如果在星尘平台没见到埋点数据,大概率是这里的问题
+ var builder = tracer?.BuildSpan(name);
builder?.Finish(this);
}
// 打断对Builder的引用,当前Span可能还被放在AsyncLocal字典中
// 也有可能原来的Builder已经上传,现在加入了新的builder集合
+#pragma warning disable CS0612 // 类型或成员已过时
Builder = null;
+#pragma warning restore CS0612 // 类型或成员已过时
}
/// 抛弃埋点,不计入采集
@@ -235,7 +249,9 @@ protected virtual void Finish()
public virtual void Abandon()
{
_finished = 1;
- Builder = null;
+ //Builder = null;
+
+ // 不能还给对象池,因为外部还有引用,Dispose尚未调用
}
/// 设置错误信息,ApiException除外
@@ -259,7 +275,7 @@ public virtual void SetError(Exception ex, Object? tag)
Error = ex.GetMessage();
// 所有异常,独立记录埋点,便于按异常分类统计
- using var span = Builder?.Tracer?.NewSpan(name, tag);
+ using var span = Tracer?.NewSpan(name, tag);
span?.AppendTag(ex.ToString());
if (span != null) span.StartTime = StartTime;
}
@@ -271,7 +287,7 @@ public virtual void SetTag(Object? tag)
{
if (tag == null) return;
- var len = Builder?.Tracer?.MaxTagLength ?? 1024;
+ var len = Tracer?.MaxTagLength ?? 1024;
if (len <= 0) return;
if (tag is String str)
@@ -296,8 +312,12 @@ public virtual void SetTag(Object? tag)
/// 清空已有数据
public void Clear()
{
+ Tracer = null;
+#pragma warning disable CS0612 // 类型或成员已过时
Builder = null;
+#pragma warning restore CS0612 // 类型或成员已过时
Id = null!;
+ Name = null!;
ParentId = null;
TraceId = null!;
StartTime = 0;
@@ -323,8 +343,7 @@ public static class SpanExtension
#region 扩展方法
private static String? GetAttachParameter(ISpan span)
{
- var builder = (span as DefaultSpan)?.Builder;
- var tracer = (builder as DefaultSpanBuilder)?.Tracer;
+ var tracer = (span as DefaultSpan)?.Tracer;
return tracer?.AttachParameter;
}
@@ -520,7 +539,7 @@ public static void AppendTag(this ISpan span, Object tag, Int64 value)
if (tag != null && span is DefaultSpan ds && ds.TraceFlag > 0)
{
- var maxLength = ds.Builder?.Tracer?.MaxTagLength ?? 1024;
+ var maxLength = ds.Tracer?.MaxTagLength ?? 1024;
if (span.Tag.IsNullOrEmpty())
span.SetTag(tag);
else if (span.Tag.Length < maxLength)
@@ -546,7 +565,7 @@ public static void AppendTag(this ISpan span, HttpResponseMessage response)
if (span is DefaultSpan ds && ds.TraceFlag > 0)
{
- var maxLength = ds.Builder?.Tracer?.MaxTagLength ?? 1024;
+ var maxLength = ds.Tracer?.MaxTagLength ?? 1024;
if (span.Tag.IsNullOrEmpty() || span.Tag.Length < maxLength)
{
// 判断类型和长度
diff --git a/NewLife.Core/Log/ISpanBuilder.cs b/NewLife.Core/Log/ISpanBuilder.cs
index ee4bafe24..d3e521583 100644
--- a/NewLife.Core/Log/ISpanBuilder.cs
+++ b/NewLife.Core/Log/ISpanBuilder.cs
@@ -65,7 +65,7 @@ public class DefaultSpanBuilder : ISpanBuilder
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
public ITracer? Tracer { get; set; }
- /// 操作名
+ /// 埋点名
public String Name { get; set; } = null!;
/// 开始时间。Unix毫秒
@@ -133,17 +133,25 @@ public void Init(String name)
public virtual ISpan Start()
{
DefaultSpan? span = null;
- if (Tracer is DefaultTracer tracer)
+ var tracer = Tracer;
+ if (tracer is DefaultTracer tracer2)
{
- span = tracer.SpanPool.Get() as DefaultSpan;
- if (span != null) span.Builder = this;
+ span = tracer2.SpanPool.Get() as DefaultSpan;
+ if (span != null)
+ {
+ span.Tracer = tracer2;
+ span.Name = Name;
+#pragma warning disable CS0612 // 类型或成员已过时
+ span.Builder = this;
+#pragma warning restore CS0612 // 类型或成员已过时
+ }
}
- span ??= new DefaultSpan(this);
+ span ??= new DefaultSpan(tracer!);
span.Start();
// 指示当前节点开始的后续节点强制采样
- if (span.TraceFlag == 0 && Tracer != null && Total < Tracer.MaxSamples) span.TraceFlag = 1;
+ if (span.TraceFlag == 0 && tracer != null && Total < tracer.MaxSamples) span.TraceFlag = 1;
return span;
}
@@ -205,9 +213,9 @@ public virtual void Finish(ISpan span)
}
// 如果埋点没有加入链表,则归还对象池
- if (!flag && Tracer is DefaultTracer tracer2 && ds != null)
+ if (!flag && Tracer is DefaultTracer tracer2)
{
- ds.Clear();
+ ds?.Clear();
tracer2.SpanPool.Return(span);
}
}
@@ -232,13 +240,21 @@ internal void Return(IList? spans)
/// 清空已有数据
public void Clear()
{
+ //!!! 不能清空Tracer,否则长时间Span完成时,Builder已被处理,Span无法创建新的Builder来统计埋点数据
Tracer = null;
+
Name = null!;
StartTime = 0;
EndTime = 0;
Value = 0;
Samples = null;
ErrorSamples = null;
+
+ _Total = 0;
+ _Errors = 0;
+ _Cost = 0;
+ MaxCost = 0;
+ MinCost = 0;
}
/// 已重载。
diff --git a/NewLife.Core/Log/ITracer.cs b/NewLife.Core/Log/ITracer.cs
index 4c44bc5df..adbe67ed9 100644
--- a/NewLife.Core/Log/ITracer.cs
+++ b/NewLife.Core/Log/ITracer.cs
@@ -66,9 +66,9 @@ static DefaultTracer()
{
// 注册默认类型,便于Json反序列化时为接口属性创造实例
var ioc = ObjectContainer.Current;
- ioc.AddTransient();
- ioc.AddTransient();
- ioc.AddTransient();
+ ioc.TryAddTransient();
+ ioc.TryAddTransient();
+ ioc.TryAddTransient();
}
#endregion
@@ -248,7 +248,7 @@ public virtual ISpan NewSpan(String name, Object? tag)
{
// 头尾是Xml/Json时,使用字符串格式
var total = pk.Total;
- if (total >= 2 && (pk[0] == '{' || pk[0] == '<' || pk[total - 1] == '}' || pk[total - 1] == '>'))
+ if (total >= 2 && (pk[0] == '{' || pk[0] == '<') && (pk[total - 1] == '}' || pk[total - 1] == '>'))
span.Tag = pk.ToStr(null, 0, len);
else
span.Tag = pk.ToHex(len / 2);
@@ -406,7 +406,7 @@ private static ISpan CreateSpan(ITracer tracer, String method, Uri uri, HttpRequ
if (span is DefaultSpan ds && ds.TraceFlag > 0 && request != null)
{
- var maxLength = ds.Builder?.Tracer?.MaxTagLength ?? 1024;
+ var maxLength = ds.Tracer?.MaxTagLength ?? 1024;
if (request.Content is ByteArrayContent content &&
content.Headers.ContentLength != null &&
content.Headers.ContentLength < 1024 * 8 &&
diff --git a/NewLife.Core/Model/Actor.cs b/NewLife.Core/Model/Actor.cs
index 9742f76df..f0d651fd0 100644
--- a/NewLife.Core/Model/Actor.cs
+++ b/NewLife.Core/Model/Actor.cs
@@ -113,7 +113,7 @@ protected override void Dispose(Boolean disposing)
{
if (Active) return _task;
- if (Tracer == null && TracerParent is DefaultSpan ds) Tracer = ds.Builder?.Tracer;
+ if (Tracer == null && TracerParent is DefaultSpan ds) Tracer = ds.Tracer;
using var span = Tracer?.NewSpan("actor:Start", Name);
diff --git a/NewLife.Core/Net/SessionBase.cs b/NewLife.Core/Net/SessionBase.cs
index baa9a1bd3..94ac808fb 100644
--- a/NewLife.Core/Net/SessionBase.cs
+++ b/NewLife.Core/Net/SessionBase.cs
@@ -337,7 +337,7 @@ public Int32 Send(ReadOnlySpan data)
if (!Open() || Client == null) return null;
- using var span = Tracer?.NewSpan($"net:{Name}:Receive", BufferSize + "");
+ using var span = Tracer?.NewSpan($"net:{Name}:Receive");
try
{
var pk = new OwnerPacket(BufferSize);
diff --git a/NewLife.Core/Net/UdpSession.cs b/NewLife.Core/Net/UdpSession.cs
index e21ea7873..17b99f756 100644
--- a/NewLife.Core/Net/UdpSession.cs
+++ b/NewLife.Core/Net/UdpSession.cs
@@ -290,7 +290,7 @@ public IOwnerPacket Receive()
if (Disposed) throw new ObjectDisposedException(GetType().Name);
if (Server?.Client == null) throw new InvalidOperationException(nameof(Server));
- using var span = Tracer?.NewSpan($"net:{Name}:Receive", Server.BufferSize + "");
+ using var span = Tracer?.NewSpan($"net:{Name}:Receive");
try
{
var ep = Remote.EndPoint as EndPoint;
@@ -314,7 +314,7 @@ public IOwnerPacket Receive()
if (Disposed) throw new ObjectDisposedException(GetType().Name);
if (Server?.Client == null) throw new InvalidOperationException(nameof(Server));
- using var span = Tracer?.NewSpan($"net:{Name}:Receive", Server.BufferSize + "");
+ using var span = Tracer?.NewSpan($"net:{Name}:Receive");
try
{
var ep = Remote.EndPoint as EndPoint;
diff --git a/Samples/Zero.HttpServer/ClientTest.cs b/Samples/Zero.HttpServer/ClientTest.cs
index 4e2788974..b411710f3 100644
--- a/Samples/Zero.HttpServer/ClientTest.cs
+++ b/Samples/Zero.HttpServer/ClientTest.cs
@@ -17,6 +17,9 @@ public static async Task HttpClientTest()
XTrace.WriteLine("");
XTrace.WriteLine("Http客户端开始连接!");
+ var tracer = DefaultTracer.Instance;
+ using var span = tracer?.NewSpan(nameof(HttpClientTest));
+
// 基础请求
var client = new HttpClient
{
@@ -27,8 +30,11 @@ public static async Task HttpClientTest()
XTrace.WriteLine(html);
// Api接口请求
- var http = new ApiHttpClient("http://127.0.0.5:8080");
- http.Log = XTrace.Log;
+ var http = new ApiHttpClient("http://127.0.0.5:8080")
+ {
+ Tracer = tracer,
+ Log = XTrace.Log
+ };
// 请求接口,返回data部分
var rs = await http.GetAsync("/user", new { act = "Delete", uid = 1234 });
@@ -68,9 +74,13 @@ public static async Task WebSocketClientTest()
XTrace.WriteLine("");
XTrace.WriteLine("WebSocketClient开始连接!");
+ var tracer = DefaultTracer.Instance;
+ using var span = tracer?.NewSpan(nameof(WebSocketClientTest));
+
var client = new WebSocketClient("ws://127.0.0.7:8080/ws")
{
Name = "小ws客户",
+ Tracer = tracer,
Log = XTrace.Log
};
if (client is TcpSession tcp) tcp.MaxAsync = 0;
diff --git a/XUnitTest.Core/Log/TracerTests.cs b/XUnitTest.Core/Log/TracerTests.cs
index a07543933..accffdb8a 100644
--- a/XUnitTest.Core/Log/TracerTests.cs
+++ b/XUnitTest.Core/Log/TracerTests.cs
@@ -380,7 +380,7 @@ public void HttpRequestMessageUriTest()
var request = new HttpRequestMessage(HttpMethod.Get, url);
var span = tracer.NewSpan(request) as DefaultSpan;
- Assert.Equal("http://sso.newlifex.com/user/query", span.Builder.Name);
+ Assert.Equal("http://sso.newlifex.com/user/query", span.Name);
Assert.StartsWith("GET http://sso.newlifex.com/user/query?id=12345", span.Tag);
}
@@ -389,7 +389,7 @@ public void HttpRequestMessageUriTest()
var request = new HttpRequestMessage(HttpMethod.Get, url);
var span = tracer.NewSpan(request) as DefaultSpan;
- Assert.Equal("user/query", span.Builder.Name);
+ Assert.Equal("user/query", span.Name);
Assert.StartsWith("GET user/query?id=12345", span.Tag);
}
}
@@ -404,7 +404,7 @@ public void WebRequestUriTest()
var request = WebRequest.CreateHttp(url);
var span = tracer.NewSpan(request) as DefaultSpan;
- Assert.Equal("http://sso.newlifex.com/user/query", span.Builder.Name);
+ Assert.Equal("http://sso.newlifex.com/user/query", span.Name);
Assert.Equal("GET http://sso.newlifex.com/user/query?id=12345", span.Tag);
}
@@ -413,7 +413,7 @@ public void WebRequestUriTest()
// var request = WebRequest.CreateHttp(new Uri(url, UriKind.RelativeOrAbsolute));
// var span = tracer.NewSpan(request) as DefaultSpan;
- // Assert.Equal("http://sso.newlifex.com/user/query", span.Builder.Name);
+ // Assert.Equal("http://sso.newlifex.com/user/query", span.Name);
// Assert.Equal("/user/query?id=12345", span.Tag);
//}
}