github.com/pinpoint-apm/pinpoint-go-agent@v1.4.1-0.20240110120318-a50c2eb18c8c/span.go (about) 1 package pinpoint 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "math/rand" 9 "strconv" 10 "strings" 11 "sync" 12 "sync/atomic" 13 "time" 14 ) 15 16 const ( 17 apiTypeDefault = 0 18 apiTypeWebRequest = 100 19 apiTypeInvocation = 200 20 noneAsyncId = 0 21 minEventDepth = 2 22 minEventSequence = 4 23 defaultEventDepth = 64 24 defaultEventSequence = 5000 25 ) 26 27 var ( 28 asyncIdGen int32 = 0 29 ) 30 31 type span struct { 32 agent *agent 33 txId TransactionId 34 spanId int64 35 parentSpanId int64 36 parentAppName string 37 parentAppType int 38 parentAppNamespace string 39 serviceType int32 40 rpcName string 41 endPoint string 42 remoteAddr string 43 acceptorHost string 44 spanEvents []*spanEvent 45 annotations annotation 46 loggingInfo int32 47 apiId int32 48 49 eventSequence int32 50 eventDepth int32 51 eventOverflow int 52 eventOverflowLog bool 53 54 startTime time.Time 55 elapsed int64 56 operationName string 57 flags int 58 err int 59 errorFuncId int32 60 errorString string 61 recovered bool 62 asyncId int32 63 asyncSequence int32 64 goroutineId int64 65 eventStack *stack 66 appendLock sync.Mutex 67 urlStat *UrlStatEntry 68 errorChains []*exception 69 } 70 71 func generateSpanId() int64 { 72 return rand.Int63() 73 } 74 75 func defaultSpan() *span { 76 span := span{} 77 78 span.parentSpanId = -1 79 span.parentAppName = "" 80 span.parentAppType = 1 //UNKNOWN 81 span.eventDepth = 1 82 span.serviceType = ServiceTypeGoApp 83 span.startTime = time.Now() 84 span.goroutineId = 0 85 span.asyncId = noneAsyncId 86 span.eventStack = &stack{} 87 span.spanEvents = make([]*spanEvent, 0) 88 span.errorChains = make([]*exception, 0) 89 90 return &span 91 } 92 93 func newSampledSpan(agent *agent, operation string, rpcName string) *span { 94 span := defaultSpan() 95 96 span.agent = agent 97 span.operationName = operation 98 span.rpcName = rpcName 99 span.apiId = agent.cacheSpanApi(operation, apiTypeWebRequest) 100 101 return span 102 } 103 104 func (span *span) EndSpan() { 105 endTime := time.Now() 106 span.elapsed = endTime.Sub(span.startTime).Milliseconds() 107 108 if span.isAsyncSpan() { 109 span.EndSpanEvent() //async span event 110 } else { 111 dropSampledActiveSpan(span) 112 collectResponseTime(span.elapsed) 113 } 114 115 if span.eventStack.len() > 0 { 116 span.eventStack.empty() 117 Log("span").Warnf("abnormal span - has unclosed event") 118 } 119 120 if span.agent.enqueueSpan(span) { 121 if len(span.errorChains) > 0 { 122 span.agent.enqueueExceptionMeta(span) 123 } 124 } else { 125 Log("span").Tracef("span channel - max capacity reached or closed") 126 } 127 128 if span.urlStat != nil { 129 span.agent.enqueueUrlStat(&urlStat{entry: span.urlStat, endTime: endTime, elapsed: span.elapsed}) 130 } 131 } 132 133 func (span *span) Inject(writer DistributedTracingContextWriter) { 134 if span.eventOverflow > 0 { 135 return 136 } 137 if se, ok := span.eventStack.peek(); ok { 138 writer.Set(HeaderTraceId, span.txId.String()) 139 140 nextSpanId := se.generateNextSpanId() 141 writer.Set(HeaderSpanId, strconv.FormatInt(nextSpanId, 10)) 142 143 writer.Set(HeaderParentSpanId, strconv.FormatInt(span.spanId, 10)) 144 writer.Set(HeaderFlags, strconv.Itoa(span.flags)) 145 writer.Set(HeaderParentApplicationName, span.agent.appName) 146 writer.Set(HeaderParentApplicationType, strconv.Itoa(int(span.agent.appType))) 147 writer.Set(HeaderParentApplicationNamespace, "") 148 149 se.endPoint = se.destinationId 150 writer.Set(HeaderHost, se.destinationId) 151 152 Log("span").Tracef("span inject: %v, %d, %d, %s", span.txId, nextSpanId, span.spanId, se.destinationId) 153 } else { 154 Log("span").Warnf("abnormal span - has no event") 155 } 156 } 157 158 func (span *span) Extract(reader DistributedTracingContextReader) { 159 tid := reader.Get(HeaderTraceId) 160 if tid != "" { 161 s := strings.Split(tid, "^") 162 span.txId.AgentId = s[0] 163 span.txId.StartTime, _ = strconv.ParseInt(s[1], 10, 0) 164 span.txId.Sequence, _ = strconv.ParseInt(s[2], 10, 0) 165 } else { 166 span.txId = span.agent.generateTransactionId() 167 } 168 169 spanid := reader.Get(HeaderSpanId) 170 if spanid != "" { 171 span.spanId, _ = strconv.ParseInt(spanid, 10, 0) 172 } else { 173 span.spanId = generateSpanId() 174 } 175 176 pspanid := reader.Get(HeaderParentSpanId) 177 if pspanid != "" { 178 span.parentSpanId, _ = strconv.ParseInt(pspanid, 10, 0) 179 } 180 181 flag := reader.Get(HeaderFlags) 182 if flag != "" { 183 span.flags, _ = strconv.Atoi(flag) 184 } 185 186 pappname := reader.Get(HeaderParentApplicationName) 187 if pappname != "" { 188 span.parentAppName = pappname 189 } 190 191 papptype := reader.Get(HeaderParentApplicationType) 192 if papptype != "" { 193 span.parentAppType, _ = strconv.Atoi(papptype) 194 } 195 196 host := reader.Get(HeaderHost) 197 if host != "" { 198 span.acceptorHost = host 199 span.endPoint = host 200 span.remoteAddr = host // for message queue (kafka, ...) 201 } 202 203 addSampledActiveSpan(span) 204 Log("span").Tracef("span extract: %s, %s, %s, %s, %s, %s", tid, spanid, pappname, pspanid, papptype, host) 205 } 206 207 func (span *span) NewSpanEvent(operationName string) Tracer { 208 cfg := span.config() 209 if span.eventSequence >= cfg.spanMaxEventSequence || span.eventDepth >= cfg.spanMaxEventDepth { 210 span.eventOverflow++ 211 if !span.eventOverflowLog { 212 Log("span").Warnf("callStack maximum depth/sequence exceeded. (depth=%d, seq=%d)", span.eventDepth, span.eventSequence) 213 span.eventOverflowLog = true 214 } 215 } else { 216 span.appendSpanEvent(newSpanEvent(span, operationName)) 217 } 218 return span 219 } 220 221 func (span *span) appendSpanEvent(se *spanEvent) { 222 span.appendLock.Lock() 223 defer span.appendLock.Unlock() 224 225 span.spanEvents = append(span.spanEvents, se) 226 span.eventStack.push(se) 227 span.eventSequence++ 228 span.eventDepth++ 229 } 230 231 func (span *span) EndSpanEvent() { 232 if span.eventOverflow > 0 { 233 span.eventOverflow-- 234 return 235 } 236 if se, ok := span.eventStack.pop(); ok { 237 se.end() 238 if !span.recovered { 239 if v := recover(); v != nil { 240 err, ok := v.(error) 241 if !ok { 242 err = errors.New(fmt.Sprint(v)) 243 } 244 se.SetError(err, "panic") 245 span.SetError(err) 246 span.recovered = true 247 panic(err) 248 } 249 } 250 } else { 251 Log("span").Warnf("abnormal span - has no event") 252 } 253 } 254 255 func (span *span) newAsyncSpan() Tracer { 256 if span.eventOverflow > 0 { 257 return NoopTracer() 258 } 259 if se, ok := span.eventStack.peek(); ok { 260 asyncSpan := defaultSpan() 261 262 asyncSpan.agent = span.agent 263 asyncSpan.txId = span.txId 264 asyncSpan.spanId = span.spanId 265 266 for se.asyncId == noneAsyncId { 267 se.asyncId = atomic.AddInt32(&asyncIdGen, 1) 268 } 269 se.asyncSeqGen++ 270 271 asyncSpan.asyncId = se.asyncId 272 asyncSpan.asyncSequence = se.asyncSeqGen 273 asyncSpan.appendSpanEvent(newSpanEventGoroutine(asyncSpan)) 274 275 return asyncSpan 276 } else { 277 Log("span").Warnf("abnormal span - has no event") 278 return NoopTracer() 279 } 280 } 281 282 func (span *span) isAsyncSpan() bool { 283 return span.asyncId != noneAsyncId 284 } 285 286 func (span *span) NewAsyncSpan() Tracer { 287 return span.newAsyncSpan() 288 } 289 290 func (span *span) NewGoroutineTracer() Tracer { 291 return span.newAsyncSpan() 292 } 293 294 func (span *span) WrapGoroutine(goroutineName string, goroutine func(context.Context), ctx context.Context) func() { 295 asyncSpan := span.newAsyncSpan() 296 297 var newCtx context.Context 298 if ctx == nil { 299 newCtx = NewContext(context.Background(), asyncSpan) 300 } else { 301 newCtx = NewContext(ctx, asyncSpan) 302 } 303 304 return func() { 305 defer asyncSpan.EndSpan() 306 defer asyncSpan.NewSpanEvent(goroutineName).EndSpanEvent() 307 goroutine(newCtx) 308 } 309 } 310 311 func (span *span) TransactionId() TransactionId { 312 return span.txId 313 } 314 315 func (span *span) SpanId() int64 { 316 return span.spanId 317 } 318 319 func (span *span) Span() SpanRecorder { 320 return span 321 } 322 323 func (span *span) SpanEvent() SpanEventRecorder { 324 if span.eventOverflow > 0 { 325 return &defaultNoopSpanEvent 326 } 327 if se, ok := span.eventStack.peek(); ok { 328 return se 329 } 330 Log("span").Warnf("abnormal span - has no event") 331 return &defaultNoopSpanEvent 332 } 333 334 func (span *span) IsSampled() bool { 335 return true 336 } 337 338 func (span *span) SetError(e error) { 339 if e == nil || span.eventOverflow > 0 { 340 return 341 } 342 343 id := span.agent.cacheError("error") 344 span.errorFuncId = id 345 span.errorString = e.Error() 346 span.err = 1 347 } 348 349 func (span *span) SetFailure() { 350 span.err = 1 351 } 352 353 func (span *span) SetServiceType(typ int32) { 354 span.serviceType = typ 355 } 356 357 func (span *span) SetRpcName(rpc string) { 358 span.rpcName = rpc 359 } 360 361 func (span *span) SetRemoteAddress(remoteAddress string) { 362 span.remoteAddr = remoteAddress 363 } 364 365 func (span *span) SetEndPoint(endPoint string) { 366 span.endPoint = endPoint 367 } 368 369 func (span *span) SetAcceptorHost(host string) { 370 span.acceptorHost = host 371 } 372 373 func (span *span) Annotations() Annotation { 374 return &span.annotations 375 } 376 377 func (span *span) SetLogging(logInfo int32) { 378 span.loggingInfo = logInfo 379 } 380 381 func (span *span) collectUrlStat(stat *UrlStatEntry) { 382 if span.config().collectUrlStat { 383 if stat.Url == "" { 384 stat.Url = "UNKNOWN_URL" 385 } 386 387 span.urlStat = stat 388 } 389 } 390 391 func (span *span) AddMetric(metric string, value interface{}) { 392 if metric == MetricURLStat { 393 span.collectUrlStat(value.(*UrlStatEntry)) 394 } 395 } 396 397 func (span *span) JsonString() []byte { 398 m := make(map[string]interface{}, 0) 399 m["RpcName"] = span.rpcName 400 m["EndPoint"] = span.endPoint 401 m["RemoteAddr"] = span.remoteAddr 402 m["Err"] = span.err 403 m["Events"] = span.spanEvents 404 m["Annotations"] = span.annotations.list 405 b, _ := json.Marshal(m) 406 return b 407 } 408 409 func (span *span) config() *Config { 410 return span.agent.config 411 } 412 413 type stack struct { 414 lock sync.RWMutex 415 top *node 416 size int 417 } 418 419 type node struct { 420 value *spanEvent 421 next *node 422 } 423 424 func (s *stack) len() int { 425 s.lock.RLock() 426 defer s.lock.RUnlock() 427 return s.size 428 } 429 430 func (s *stack) push(v *spanEvent) { 431 s.lock.Lock() 432 defer s.lock.Unlock() 433 434 s.top = &node{value: v, next: s.top} 435 s.size++ 436 } 437 438 func (s *stack) pop() (*spanEvent, bool) { 439 s.lock.Lock() 440 defer s.lock.Unlock() 441 442 if s.size > 0 { 443 save := s.top.value 444 s.top = s.top.next 445 s.size-- 446 return save, true 447 } 448 return nil, false 449 } 450 451 func (s *stack) peek() (*spanEvent, bool) { 452 s.lock.RLock() 453 defer s.lock.RUnlock() 454 455 if s.size > 0 { 456 return s.top.value, true 457 } 458 return nil, false 459 } 460 461 func (s *stack) empty() { 462 s.lock.Lock() 463 defer s.lock.Unlock() 464 465 for s.size > 0 { 466 s.top.value.end() 467 s.top = s.top.next 468 s.size-- 469 } 470 }