refactor(otelTrace): 替换CreateTraceableContext为CreateLinkContext
- 删除CreateTraceableContext函数,改用CreateLinkContext实现相同功能 - 修改相关测试用例,验证CreateLinkContext的上下文链路和属性 - 优化span创建逻辑,保持trace id一致,生成不同span id - 保持上下文关联但不继承取消信号,增强追踪准确性 fix(order): 增加更新操作错误日志打印 - 在更新发送计数失败时添加详细日志输出 - 在更新池订单ID失败时添加错误日志 - 确保错误场景能够被及时监控和排查 fix(flyfishv2): 扩大发卡请求超时时间至30秒 - 将flyfishv2发卡请求的超时时间从10秒调整为30秒 - 提高接口稳定性,避免偶发超时问题 fix(flyfishv2): 调整订单状态日志信息 - 移除重复记录订单状态字段的日志内容 - 优化日志输出,突出关键字段bankOrderId feat(scanController): 使用CreateLinkContext追踪SubmitPool流程 - 使用CreateLinkContext创建链路追踪上下文 - 添加span属性记录bankOrderId - 在提交流程中增加事件标记StartScan和EndScan - 确保请求链路完整便于性能监控和错误排查 fix(poolService): 优化redis错误日志及span事件处理 - 添加获取用户订单失败的错误日志 - 将acquire user order事件改为先设置属性再添加事件 - 删除无用日志调用,减少日志冗余 - 确保追踪span事件表示清晰准确 chore(deps): 更新Dockerfile代理配置秘钥 - 更新Dockerfile中proxyUrl、proxyAuthKey和proxyAuthPwd - 修改distinct参数为true,提高代理请求正确性 style(otelTrace): 调整mustSampled数组增加SubmitOrder - 在mustSampled列表中添加“SubmitOrder”标签 - 保持采样清单同步,确保重要操作被采样记录
This commit is contained in:
@@ -22,9 +22,9 @@ ENV TZ=Asia/Shanghai \
|
||||
shopAddr="" \
|
||||
proxy="" \
|
||||
proxyName="qkgo" \
|
||||
proxyUrl="https://share.proxy.qg.net/get?key=7ASQH2BI&num=2&area=&isp=0&format=txt&seq=\n&distinct=false" \
|
||||
proxyAuthKey="7ASQH2BI" \
|
||||
proxyAuthPwd="34D6652FE7B6"
|
||||
proxyUrl="https://share.proxy.qg.net/get?key=E4WS5YZV&num=2&area=&isp=0&format=txt&seq=\n&distinct=true" \
|
||||
proxyAuthKey="E4WS5YZV" \
|
||||
proxyAuthPwd="C474B2794C4E"
|
||||
|
||||
# Switch to root to perform system operations
|
||||
USER root
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"gateway/internal/service/supplier/t_mall_game"
|
||||
"gateway/internal/service/supplier/third_party"
|
||||
"gateway/internal/utils"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -288,12 +289,11 @@ func (c *ScanController) Scan() {
|
||||
return
|
||||
}
|
||||
|
||||
otelTrace.Logger.WithContext(ctx).Info("supplierCode", zap.String("supplierCode", supplierCode))
|
||||
|
||||
submitPool.Go(func() {
|
||||
ctx2, span2 := otelTrace.CreateLinkContext(c.Ctx.Request.Context(), "ScanController.SubmitPool")
|
||||
ctx2, span2 := otelTrace.CreateLinkContext(ctx, "ScanController.SubmitPool")
|
||||
defer span2.End()
|
||||
span2.SetAttributes(attribute.String("bankOrderId", orderInfo.BankOrderId))
|
||||
span2.AddEvent("StartScan")
|
||||
|
||||
scanData := supplierByCode.Scan(ctx2, orderInfo, p.RoadInfo, p.MerchantInfo)
|
||||
order.InsertCardReturnDataByBankId(ctx2, orderInfo.BankOrderId, scanData.ReturnData)
|
||||
span2.AddEvent("EndScan")
|
||||
|
||||
@@ -75,7 +75,11 @@ func UpdateSendCount(ctx context.Context, orderId string) bool {
|
||||
"send_count": orm.ColValue(orm.ColAdd, 1),
|
||||
"is_amount_different": 1,
|
||||
})
|
||||
return err == nil
|
||||
if err != nil {
|
||||
otelTrace.Logger.WithContext(ctx).Error("update send count fail: ", zap.Error(err))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func UpdatePoolOrderId(ctx context.Context, orderId, poolOrderId, bankTransId string) bool {
|
||||
@@ -83,7 +87,11 @@ func UpdatePoolOrderId(ctx context.Context, orderId, poolOrderId, bankTransId st
|
||||
"pool_order_id": poolOrderId,
|
||||
"bank_trans_id": bankTransId,
|
||||
})
|
||||
return err == nil
|
||||
if err != nil {
|
||||
otelTrace.Logger.WithContext(ctx).Error("update pool order id fail: ", zap.Error(err))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func UpdateOrderAmount(ctx context.Context, orderId string, orderAmount float64) bool {
|
||||
|
||||
@@ -22,17 +22,12 @@ const (
|
||||
|
||||
// BatchTimeout 批量传输配置 - 优化高负载场景性能
|
||||
BatchTimeout = 10 * time.Second // 批量发送间隔,平衡实时性和性能
|
||||
MaxBatchSize = 1000 // 队列缓冲大小,适应突发流量
|
||||
MaxExportBatchSize = 512 // 单次导出最大批量,避免单次传输过大
|
||||
MaxQueueSize = 2048 // 最大队列大小,防止内存溢出
|
||||
|
||||
// DefaultSamplingRatio 采样配置 - 生产环境资源控制
|
||||
DefaultSamplingRatio = 0.5 // 默认采样率10%,平衡观测性和性能
|
||||
HighLoadSamplingRatio = 0.1 // 高负载时采样率5%,保护系统稳定性
|
||||
|
||||
// MaxConcurrentExports 资源限制配置 - 防止资源竞争
|
||||
MaxConcurrentExports = 10 // 最大并发导出数,控制资源使用
|
||||
MemoryLimitMB = 100 // 内存使用限制(MB)
|
||||
DefaultSamplingRatio = 0.5 // 默认采样率50%,平衡观测性和性能
|
||||
HighLoadSamplingRatio = 0.1 // 高负载时采样率10%,保护系统稳定性
|
||||
)
|
||||
|
||||
// CircuitBreakerState 熔断器状态
|
||||
|
||||
@@ -230,37 +230,37 @@ func TestLinkContextIndependence(t *testing.T) {
|
||||
<-done
|
||||
}
|
||||
|
||||
func TestCreateTraceableContext(t *testing.T) {
|
||||
func TestCreateLinkContextBasic(t *testing.T) {
|
||||
// 创建父上下文和span
|
||||
ctx := context.Background()
|
||||
_, parentSpan := otel.Tracer("test").Start(ctx, "ParentSpan")
|
||||
defer parentSpan.End()
|
||||
|
||||
// 创建可追踪的上下文
|
||||
traceableCtx, traceableSpan := CreateTraceableContext(ctx, "TraceableOperation")
|
||||
defer traceableSpan.End()
|
||||
// 创建link ctx
|
||||
linkCtx, linkSpan := CreateLinkContext(ctx, "LinkOperation")
|
||||
defer linkSpan.End()
|
||||
|
||||
// 验证traceableCtx包含父span的上下文
|
||||
traceableSpanCtx := trace.SpanContextFromContext(traceableCtx)
|
||||
if !traceableSpanCtx.IsValid() {
|
||||
t.Error("traceableCtx应该包含有效的span上下文")
|
||||
// 验证linkCtx包含父span的上下文
|
||||
linkSpanCtx := trace.SpanContextFromContext(linkCtx)
|
||||
if !linkSpanCtx.IsValid() {
|
||||
t.Error("linkCtx应该包含有效的span上下文")
|
||||
}
|
||||
|
||||
// 验证父span和traceable span的trace ID相同
|
||||
// 验证父span和link span的trace ID相同
|
||||
parentSpanCtx := parentSpan.SpanContext()
|
||||
if traceableSpanCtx.TraceID() != parentSpanCtx.TraceID() {
|
||||
t.Error("traceable span应该与父span有相同的trace ID")
|
||||
if linkSpanCtx.TraceID() != parentSpanCtx.TraceID() {
|
||||
t.Error("link span应该与父span有相同的trace ID")
|
||||
}
|
||||
|
||||
// 验证traceable span的span ID不同
|
||||
if traceableSpanCtx.SpanID() == parentSpanCtx.SpanID() {
|
||||
t.Error("traceable span应该有不同的span ID")
|
||||
// 验证link span的span ID不同
|
||||
if linkSpanCtx.SpanID() == parentSpanCtx.SpanID() {
|
||||
t.Error("link span应该有不同的span ID")
|
||||
}
|
||||
|
||||
// 验证traceable span包含正确的属性
|
||||
span := trace.SpanFromContext(traceableCtx)
|
||||
// 验证link span包含正确的属性
|
||||
span := trace.SpanFromContext(linkCtx)
|
||||
if span == nil {
|
||||
t.Error("traceableCtx应该包含有效的span")
|
||||
t.Error("linkCtx应该包含有效的span")
|
||||
}
|
||||
|
||||
// 验证span属性
|
||||
@@ -270,34 +270,34 @@ func TestCreateTraceableContext(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTraceableContextInGoroutine(t *testing.T) {
|
||||
func TestLinkContextInGoroutineAdvanced(t *testing.T) {
|
||||
// 创建父上下文和span
|
||||
ctx := context.Background()
|
||||
_, parentSpan := otel.Tracer("test").Start(ctx, "ParentSpan")
|
||||
defer parentSpan.End()
|
||||
|
||||
// 在goroutine中使用traceable ctx
|
||||
// 在goroutine中使用link ctx
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
traceableCtx, traceableSpan := CreateTraceableContext(ctx, "GoroutineTraceableOperation")
|
||||
defer traceableSpan.End()
|
||||
linkCtx, linkSpan := CreateLinkContext(ctx, "GoroutineLinkOperation")
|
||||
defer linkSpan.End()
|
||||
|
||||
// 验证traceableCtx在goroutine中仍然有效
|
||||
traceableSpanCtx := trace.SpanContextFromContext(traceableCtx)
|
||||
if !traceableSpanCtx.IsValid() {
|
||||
t.Error("goroutine中的traceableCtx应该包含有效的span上下文")
|
||||
// 验证linkCtx在goroutine中仍然有效
|
||||
linkSpanCtx := trace.SpanContextFromContext(linkCtx)
|
||||
if !linkSpanCtx.IsValid() {
|
||||
t.Error("goroutine中的linkCtx应该包含有效的span上下文")
|
||||
}
|
||||
|
||||
// 验证trace ID链接
|
||||
parentSpanCtx := parentSpan.SpanContext()
|
||||
if traceableSpanCtx.TraceID() != parentSpanCtx.TraceID() {
|
||||
if linkSpanCtx.TraceID() != parentSpanCtx.TraceID() {
|
||||
t.Error("goroutine中的span应该与父span有相同的trace ID")
|
||||
}
|
||||
|
||||
// 验证span属性
|
||||
span := trace.SpanFromContext(traceableCtx)
|
||||
span := trace.SpanFromContext(linkCtx)
|
||||
if span == nil {
|
||||
t.Error("goroutine中的traceableCtx应该包含有效的span")
|
||||
t.Error("goroutine中的linkCtx应该包含有效的span")
|
||||
}
|
||||
|
||||
done <- true
|
||||
@@ -307,20 +307,20 @@ func TestTraceableContextInGoroutine(t *testing.T) {
|
||||
<-done
|
||||
}
|
||||
|
||||
func TestTraceableContextAttributes(t *testing.T) {
|
||||
func TestLinkContextAttributes(t *testing.T) {
|
||||
// 创建父上下文和span
|
||||
ctx := context.Background()
|
||||
_, parentSpan := otel.Tracer("test").Start(ctx, "ParentSpan")
|
||||
defer parentSpan.End()
|
||||
|
||||
// 创建可追踪的上下文
|
||||
traceableCtx, traceableSpan := CreateTraceableContext(ctx, "TestOperation")
|
||||
defer traceableSpan.End()
|
||||
// 创建link上下文
|
||||
linkCtx, linkSpan := CreateLinkContext(ctx, "TestOperation")
|
||||
defer linkSpan.End()
|
||||
|
||||
// 验证span包含正确的属性
|
||||
span := trace.SpanFromContext(traceableCtx)
|
||||
span := trace.SpanFromContext(linkCtx)
|
||||
if span == nil {
|
||||
t.Error("traceableCtx应该包含有效的span")
|
||||
t.Error("linkCtx应该包含有效的span")
|
||||
}
|
||||
|
||||
// 验证span上下文
|
||||
|
||||
@@ -18,6 +18,7 @@ type traceIDRatioSampler struct {
|
||||
var mustSampled = []string{
|
||||
"PayNotify",
|
||||
"HandleSendCardTask",
|
||||
"SubmitOrder",
|
||||
}
|
||||
|
||||
// SamplingPriority 强制采样
|
||||
|
||||
@@ -74,30 +74,6 @@ func CreateAsyncContext(ctx context.Context, operationName string) (context.Cont
|
||||
)
|
||||
}
|
||||
|
||||
// CreateTraceableContext 创建一个可追踪的上下文,传递完整的trace和span信息
|
||||
// 这个函数确保子ctx能够访问父ctx中的所有追踪信息
|
||||
func CreateTraceableContext(ctx context.Context, operationName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
|
||||
// 获取父span的上下文
|
||||
parentSpanCtx := trace.SpanContextFromContext(ctx)
|
||||
|
||||
// 创建新的上下文,保持追踪关联但不继承取消信号
|
||||
linkCtx := trace.ContextWithSpanContext(context.Background(), parentSpanCtx)
|
||||
|
||||
// 添加更多追踪属性
|
||||
traceOpts := append(opts,
|
||||
trace.WithLinks(trace.Link{SpanContext: parentSpanCtx}),
|
||||
trace.WithSpanKind(trace.SpanKindInternal),
|
||||
trace.WithAttributes(
|
||||
attribute.String("operation", operationName),
|
||||
attribute.String("parent.trace_id", parentSpanCtx.TraceID().String()),
|
||||
attribute.String("parent.span_id", parentSpanCtx.SpanID().String()),
|
||||
attribute.String("context_type", "traceable"),
|
||||
),
|
||||
)
|
||||
|
||||
return otel.Tracer("traceable").Start(linkCtx, operationName, traceOpts...)
|
||||
}
|
||||
|
||||
// SetSpanError 设置span的错误状态,优化错误追踪
|
||||
func SetSpanError(span trace.Span, err error, message string) {
|
||||
if span == nil {
|
||||
|
||||
@@ -159,7 +159,7 @@ func (c *FlyFishV2Impl) PayNotify() {
|
||||
}
|
||||
|
||||
if orderInfo.Status != "wait" {
|
||||
otelTrace.Logger.WithContext(ctx).Error("【飞鱼】订单状态不正确", zap.String("status", orderInfo.Status), zap.String("bankOrderId", orderInfo.BankOrderId))
|
||||
otelTrace.Logger.WithContext(ctx).Error("【飞鱼】订单状态不正确", zap.String("bankOrderId", orderInfo.BankOrderId))
|
||||
c.Ctx.WriteString("订单已经回调")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func (s *SendCardTaskTypeFlyFishV2) HandleSendCardTask(ctx context.Context, orde
|
||||
SetHeader("origin", "https://apify.fkpay.online").
|
||||
SetHeader("user-agent", useragent.GetUserAgentByPlatform(useragent.PlatformPhone)).
|
||||
SetHeader("referer", "https://apify.fkpay.online/show.html?orderId=FY17568845864231914279").
|
||||
SetTimeout(time.Second * 10).OnBeforeRequest(func(client *resty.Client, request *resty.Request) error {
|
||||
SetTimeout(time.Second * 30).OnBeforeRequest(func(client *resty.Client, request *resty.Request) error {
|
||||
proxy, err2 := utils.GetProxy(ctx, utils.GenerateId(), "SendCardTaskTypeFlyFishV2_cardTask")
|
||||
otelTrace.Logger.WithContext(ctx).Info("获取代理", zap.String("proxy", proxy))
|
||||
if err2 != nil {
|
||||
|
||||
@@ -436,7 +436,6 @@ func (s *OrderPoolServiceImpl) matchOrdersForFaceValue(ctx context.Context, chan
|
||||
// 获取用户订单
|
||||
var task card_sender.SendCardTask
|
||||
if err = s.redisClient.LPopUnmarshal(ctx, customerKey, &task); err != nil {
|
||||
s.metrics.RecordError("redis")
|
||||
otelTrace.Logger.WithContext(ctx).Error("获取用户订单失败", zap.Error(err))
|
||||
// 获取用户订单失败时,将生产订单重新放回池中
|
||||
if err = s.redisClient.LPush(ctx, produceKey, produceOrderItem); err != nil {
|
||||
@@ -445,7 +444,8 @@ func (s *OrderPoolServiceImpl) matchOrdersForFaceValue(ctx context.Context, chan
|
||||
return
|
||||
}
|
||||
|
||||
span.AddEvent("acquire user order", trace.WithAttributes(attribute.String("bankOrderId", task.LocalOrderID)))
|
||||
span.SetAttributes(attribute.String("bankOrderId", task.LocalOrderID))
|
||||
span.AddEvent("acquire user order")
|
||||
if task.SendCardTaskType == "" {
|
||||
task.SendCardTaskType = channel
|
||||
}
|
||||
@@ -481,7 +481,6 @@ func (s *OrderPoolServiceImpl) matchOrdersForFaceValue(ctx context.Context, chan
|
||||
// 处理发卡任务,带重试机制
|
||||
var retryCount int
|
||||
for retryCount < s.config.MaxRetryCount {
|
||||
otelTrace.Logger.WithContext(ctx).Info("处理发卡任务", zap.String("roadUid", roadUid), zap.Float64("faceValue", faceValue), zap.Any("produceOrderItem", produceOrderItem), zap.Any("task", task))
|
||||
err = sendCardTaskType.HandleSendCardTask(ctx, produceOrderItem, task)
|
||||
|
||||
if err == nil {
|
||||
|
||||
Reference in New Issue
Block a user