| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package trace
- import (
- "fmt"
- "net/http"
- "strings"
- "time"
- "yunion.io/x/pkg/util/timeutils"
- "yunion.io/x/pkg/utils"
- )
- type TraceKind string
- const UNKNOWN_SERVICE_NAME string = "(unknown_service)"
- const (
- X_YUNION_PEER_SERVICE_NAME = "X-Yunion-Peer-Service-Name"
- // X_YUNION_SERVICE_NAME = "X-Yunion-Service-Name"
- X_YUNION_TRACE_ID = "X-Yunion-STrace-Id"
- X_YUNION_SPAN_NAME = "X-Yunion-Span-Name"
- X_YUNION_PARENT_ID = "X-Yunion-Parent-Id"
- X_YUNION_SPAN_ID = "X-Yunion-Span-Id"
- X_YUNION_TRACE_DEBUG = "X-Yunion-STrace-Debug"
- X_YUNION_REMOTE_ADDR = "X-Yunion-Remote-Addr"
- X_YUNION_TRACE_TAG = "X-Yunion-STrace-Tag-"
- )
- const (
- TRACE_KIND_CLIENT TraceKind = "CLIENT"
- TRACE_KIND_SERVER TraceKind = "SERVER"
- )
- type STraceEndpoint struct {
- ServiceName string
- Addr string
- Port int
- }
- type STrace struct {
- TraceId string
- Name string
- ParentId string
- Id string
- clientId int // valid for ServerTrace
- Kind TraceKind
- Timestamp time.Time
- Duration time.Duration
- Debug bool
- Shared bool
- LocalEndpoint STraceEndpoint
- RemoteEndpoint STraceEndpoint
- Tags map[string]string
- }
- func (tr *STrace) IsZero() bool {
- return len(tr.TraceId) == 0
- }
- func (tr *STrace) String() string {
- return fmt.Sprintf("[%s %s.%s] %s %s %fms", timeutils.ShortDate(tr.Timestamp), tr.TraceId, tr.Id,
- tr.Kind, tr.Name, tr.Duration.Seconds()*1000)
- }
- func StartServerTrace(w http.ResponseWriter, r *http.Request, localSpanName string, localServiceName string, srvTags map[string]string) *STrace {
- traceId := r.Header.Get(X_YUNION_TRACE_ID)
- var spanId string
- var spanName string
- var parentId string
- var peerSrvName string
- var debug bool
- var localAddr string
- var localPort int
- var isBorder bool
- if len(traceId) == 0 {
- isBorder = true
- traceId = utils.GenRequestId(4)
- spanId = "0"
- spanName = localSpanName
- parentId = ""
- peerSrvName = UNKNOWN_SERVICE_NAME
- debug = true
- localAddr = ""
- localPort = 0
- } else {
- remoteAddr := r.Header.Get(X_YUNION_REMOTE_ADDR)
- if len(remoteAddr) > 0 {
- addr, port := utils.GetAddrPort(remoteAddr)
- localAddr = addr
- localPort = port
- }
- spanId = r.Header.Get(X_YUNION_SPAN_ID)
- spanName = localSpanName
- if len(spanName) == 0 {
- spanName = r.Header.Get(X_YUNION_SPAN_NAME)
- }
- parentId = r.Header.Get(X_YUNION_PARENT_ID)
- peerSrvName = r.Header.Get(X_YUNION_PEER_SERVICE_NAME)
- if r.Header.Get(X_YUNION_TRACE_DEBUG) == "true" {
- debug = true
- } else {
- debug = false
- }
- }
- shared := false
- localEp := STraceEndpoint{ServiceName: localServiceName,
- Addr: localAddr, Port: localPort}
- remoteEp := STraceEndpoint{ServiceName: peerSrvName}
- if len(r.RemoteAddr) != 0 {
- addr, port := utils.GetAddrPort(r.RemoteAddr)
- remoteEp.Addr = addr
- remoteEp.Port = port
- }
- var tags map[string]string
- if srvTags != nil {
- tags = make(map[string]string)
- for k, v := range srvTags {
- tags[k] = v
- }
- }
- trace := STrace{TraceId: traceId,
- Name: spanName,
- ParentId: parentId,
- Id: spanId,
- clientId: 0, // valid for ServerTrace
- Kind: TRACE_KIND_SERVER,
- Timestamp: time.Now(),
- Duration: 0,
- Debug: debug,
- Shared: shared,
- LocalEndpoint: localEp,
- RemoteEndpoint: remoteEp,
- Tags: tags,
- }
- if !isBorder {
- // do not distribute trace info across border
- w.Header().Set(X_YUNION_SPAN_NAME, spanName)
- w.Header().Set(X_YUNION_PEER_SERVICE_NAME, localServiceName)
- w.Header().Set(X_YUNION_REMOTE_ADDR, r.RemoteAddr)
- if tags != nil {
- for k, v := range tags {
- w.Header().Set(X_YUNION_TRACE_TAG+k, v)
- }
- }
- }
- return &trace
- }
- func (tr *STrace) EndTrace() {
- tr.Duration = time.Now().Sub(tr.Timestamp)
- SubmitTrace(tr)
- }
- func StartClientTrace(ctxTrace *STrace, remoteAddr string, remotePort int, localServiceName string) *STrace {
- var traceId string
- var parentId string
- var spanId string
- var debug bool
- var share bool
- if ctxTrace != nil {
- traceId = ctxTrace.TraceId
- parentId = ctxTrace.Id
- spanId = fmt.Sprintf("%s.%d", ctxTrace.Id, ctxTrace.clientId)
- ctxTrace.clientId += 1
- debug = ctxTrace.Debug
- share = ctxTrace.Shared
- } else {
- traceId = utils.GenRequestId(4)
- parentId = ""
- spanId = "0"
- debug = true
- share = false
- }
- localEp := STraceEndpoint{ServiceName: localServiceName,
- Addr: "", Port: 0}
- remoteEp := STraceEndpoint{ServiceName: "",
- Addr: remoteAddr, Port: remotePort}
- trace := STrace{TraceId: traceId,
- Name: "",
- ParentId: parentId,
- Id: spanId,
- Kind: TRACE_KIND_CLIENT,
- Timestamp: time.Now(),
- Duration: 0,
- Debug: debug,
- Shared: share,
- LocalEndpoint: localEp,
- RemoteEndpoint: remoteEp,
- }
- return &trace
- }
- func (tr *STrace) EndClientTraceHeader(header http.Header) {
- spanName := header.Get(X_YUNION_SPAN_NAME)
- srvName := header.Get(X_YUNION_PEER_SERVICE_NAME)
- localAddr := header.Get(X_YUNION_REMOTE_ADDR)
- tags := make(map[string]string)
- for k, v := range header {
- if strings.HasPrefix(k, X_YUNION_TRACE_TAG) {
- tagName := k[:len(X_YUNION_TRACE_TAG)]
- tags[tagName] = v[0]
- }
- }
- tr.EndClientTrace(spanName, srvName, localAddr, tags)
- }
- func (tr *STrace) EndClientTrace(spanName, remoteServiceName, localAddr string, tags map[string]string) {
- tr.Name = spanName
- tr.RemoteEndpoint.ServiceName = remoteServiceName
- var addr string
- var port int
- if len(localAddr) > 0 {
- addr, port = utils.GetAddrPort(localAddr)
- } else {
- addr = fmt.Sprintf("%s", utils.GetOutboundIP())
- }
- tr.LocalEndpoint.Addr = addr
- tr.LocalEndpoint.Port = port
- if tags != nil {
- if tr.Tags == nil {
- tr.Tags = make(map[string]string)
- }
- for k, v := range tags {
- tr.Tags[k] = v
- }
- }
- tr.EndTrace()
- }
- func (tr *STrace) AddClientRequestHeader(header http.Header) {
- header.Set(X_YUNION_TRACE_ID, tr.TraceId)
- header.Set(X_YUNION_REMOTE_ADDR, fmt.Sprintf("%s:%d", tr.RemoteEndpoint.Addr, tr.RemoteEndpoint.Port))
- header.Set(X_YUNION_SPAN_ID, tr.Id)
- header.Set(X_YUNION_SPAN_NAME, tr.Name)
- header.Set(X_YUNION_PARENT_ID, tr.ParentId)
- header.Set(X_YUNION_PEER_SERVICE_NAME, tr.LocalEndpoint.ServiceName)
- if tr.Debug {
- header.Set(X_YUNION_TRACE_DEBUG, "true")
- }
- }
- func SubmitTrace(trace *STrace) {
- }
|