basictracer-go原始碼閱讀——examples(完結)

cdh0805010118發表於2018-07-05

在服務啟動時,開啟兩個 goroutine,一個為 client,終端輸入發出 web 請求;一個為 http server,監聽埠為 8080。這裡不用瀏覽器或者其他做 client 的原因是,需要 client 端建立 trace,這樣才能夠在 client/server 跨程式形成呼叫鏈。 client 直接回車,則結束程式。

在啟動兩個 goroutine 之前,初始化了 global tracer, 並指定了 Collector 和 Storage 於一身的 TrivialRecorder. 它的 RecordSpan 方法只是輸出到終端的 Span 所有相關資訊:操作名、建立時間、生命週期時間、日誌列表長度、上下文攜帶資訊和日誌列表中的每行日誌

其中:dapprish/random.go 沒有作用。

Server

該服務啟動了 http 的 8080 埠服務,接受所有請求,http 服務的網路傳輸資料 Carrier 是採用的 TextMapPropagation 協議

它會在每個請求到來時,會根據 Client 的 SpanContext 資訊建立一個名稱為"ServerSpan"的 Span。這個 DEMO 健壯性差,容易 panic 的原因在於:

如果非下面的Client請求,而是其他web請求進來的,則不會帶有Carrier的網路傳輸資料,則在TextMapPropagation的Extract解析時,報ErrSpanContextNotFound錯誤, 則在server中直接panic掉

獲取 request body 資料流後,通過 Span.Logs 記錄請求資料,並通過 span.Finish 方法儲存 RawSpan 資料={TraceID、SpanID、Sampled 和 Baggage}

Client

client 通過終端輸入傳送 web http POST 請求,它首先建立名稱為"getInput"的 Span, 並在 span 的 logs 中記錄 ctx、user text、返回 response 等內容;以及攜帶除了 TraceID、SpanID、Sampled 和 Baggage{"User": 當前終端登入使用者名稱}, 當 span 生命週期結束時,通過 span.Finish 方法儲存 RawSpan 資訊到記憶體中。

輸入"hello,world",執行結果如下所示:

Enter text (empty string to exit): hello,world
RecordSpan: serverSpan[2018-07-05 14:19:44.151121569 +0800 CST m=+7.236240362, 57.771µs us] --> 1 logs. context: {5671206282793949525 9024173529197870936 false map[user:chenchao]}; baggage: map[user:chenchao]
    log 0 @ 2018-07-05 14:19:44.151178152 +0800 CST m=+7.236296945: [request body:hello,world]
RecordSpan: getInput[2018-07-05 14:19:36.916512195 +0800 CST m=+0.001382988, 7.235279179s us] --> 3 logs. context: {5671206282793949525 978135273461507120 false map[User:chenchao]}; baggage: map[User:chenchao]
    log 0 @ 2018-07-05 14:19:36.916526835 +0800 CST m=+0.001397628: [ctx:context.Background.WithValue(opentracing.contextKey{}, &basictracer.spanImpl{tracer:(*basictracer.tracerImpl)(0xc4201340c0), event:(func(basictracer.SpanEvent))(nil), Mutex:sync.Mutex{state:1, sema:0x0}, raw:basictracer.RawSpan{Context:basictracer.SpanContext{TraceID:0x4eb42c111de59955, SpanID:0xd9308d94cf3e430, Sampled:false, Baggage:map[string]string{"User":"chenchao"}}, ParentSpanID:0x0, Operation:"getInput", Start:time.Time{wall:0xbec78bfe36a0ddc3, ext:1382988, loc:(*time.Location)(0x14960c0)}, Duration:7235279179, Tags:opentracing.Tags(nil), Logs:[]opentracing.LogRecord{opentracing.LogRecord{Timestamp:time.Time{wall:0xbec78bfe36a116f3, ext:1397628, loc:(*time.Location)(0x14960c0)}, Fields:[]log.Field{log.Field{key:"ctx", fieldType:10, numericVal:0, stringVal:"", interfaceVal:(*context.valueCtx)(0xc4200a6f00)}}}, opentracing.LogRecord{Timestamp:time.Time{wall:0xbec78c0008cf8373, ext:7232936124, loc:(*time.Location)(0x14960c0)}, Fields:[]log.Field{log.Field{key:"user text", fieldType:0, numericVal:0, stringVal:"hello,world", interfaceVal:interface {}(nil)}}}, opentracing.LogRecord{Timestamp:time.Time{wall:0xbec78c0009085b42, ext:7236661387, loc:(*time.Location)(0x14960c0)}, Fields:[]log.Field{log.Field{key:"response", fieldType:10, numericVal:0, stringVal:"", interfaceVal:(*http.Response)(0xc42018a090)}}}}}, numDroppedLogs:0})]
    log 1 @ 2018-07-05 14:19:44.147817331 +0800 CST m=+7.232936124: [user text:hello,world]
    log 2 @ 2018-07-05 14:19:44.151542594 +0800 CST m=+7.236661387: [response:&{200 OK 200 HTTP/1.1 1
1 map[Date:[Thu, 05 Jul 2018 06:19:44 GMT] Content-Length:[0]] {} 0 [] false false map[] 0xc42014c000
<nil>}]

總結

opentracing-go 庫是對 OpenTracing 標準的程式碼正規化表達,而 basictracer-go 是對前者的最小子集擴充套件和實現,理論上這個 basictracer-go 已經可以進行業務開發和使用了,但是這個庫還非常弱,主要表現在:collector 和 storage 基於一身,且還是基於記憶體的,沒有 dashboard UI 支援,無法用於生產。雖然無法用於生產,但是 Span 的實現,Carrier 的支援已經做得很好了,同時這個庫希望廠商採用 OpenTracing 標準實現時,可以把它作為中間層或者元件使用,因為它對廠商開放了一些介面自定義實現,例如:Carrier 的 AccessPropagation(IPC/RPC 資料轉換和儲存),SpanRecord 介面(RawSpan 資訊儲存)。但是廠商也可以完全自己基於 opentracing-go 設計一套完整的分散式跟蹤系統,不用再在 opentracing-go 和廠商中間加一層 basictracer-go。

更多原創文章乾貨分享,請關注公眾號
  • basictracer-go原始碼閱讀——examples(完結)
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章