W3Cschool
恭喜您成為首批注冊(cè)用戶(hù)
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
我們?cè)賮?lái)看一個(gè)相對(duì)完整一點(diǎn)的例子,包含幾個(gè)常用核心組件的鏈路跟蹤示例,示例代碼地址:https://github.com/gogf/gf/tree/master/example/trace/http_with_db
package main
import (
"github.com/gogf/gf/contrib/trace/jaeger/v2"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/net/gtrace"
"github.com/gogf/gf/v2/os/gctx"
)
const (
ServiceName = "http-client-with-db"
JaegerUdpEndpoint = "localhost:6831"
)
func main() {
var ctx = gctx.New()
tp, err := jaeger.Init(ServiceName, JaegerUdpEndpoint)
if err != nil {
g.Log().Fatal(ctx, err)
}
defer tp.Shutdown(ctx)
StartRequests()
}
func StartRequests() {
ctx, span := gtrace.NewSpan(gctx.New(), "StartRequests")
defer span.End()
var (
err error
client = g.Client()
)
// Add user info.
var insertRes = struct {
ghttp.DefaultHandlerResponse
Data struct{ Id int64 } `json:"data"`
}{}
err = client.PostVar(ctx, "http://127.0.0.1:8199/user/insert", g.Map{
"name": "john",
}).Scan(&insertRes)
if err != nil {
panic(err)
}
g.Log().Info(ctx, "insert result:", insertRes)
if insertRes.Data.Id == 0 {
g.Log().Error(ctx, "retrieve empty id string")
return
}
// Query user info.
var queryRes = struct {
ghttp.DefaultHandlerResponse
Data struct{ User gdb.Record } `json:"data"`
}{}
err = client.GetVar(ctx, "http://127.0.0.1:8199/user/query", g.Map{
"id": insertRes.Data.Id,
}).Scan(&queryRes)
if err != nil {
panic(err)
}
g.Log().Info(ctx, "query result:", queryRes)
// Delete user info.
var deleteRes = struct {
ghttp.DefaultHandlerResponse
}{}
err = client.PostVar(ctx, "http://127.0.0.1:8199/user/delete", g.Map{
"id": insertRes.Data.Id,
}).Scan(&deleteRes)
if err != nil {
panic(err)
}
g.Log().Info(ctx, "delete result:", deleteRes)
}
客戶(hù)端代碼簡(jiǎn)要說(shuō)明:
首先,客戶(hù)端也是需要通過(guò)?jaeger.Init
?方法初始化?Jaeger
?。
在本示例中,我們通過(guò)HTTP客戶(hù)端向服務(wù)端發(fā)起了3次請(qǐng)求:
/user/insert
? 用于新增一個(gè)用戶(hù)信息,成功后返回用戶(hù)的ID。/user/query
? 用于查詢(xún)用戶(hù),使用前一個(gè)接口返回的用戶(hù)ID。/user/delete
? 用于刪除用戶(hù),使用之前接口返回的用戶(hù)ID。package main
import (
"context"
"fmt"
"time"
"github.com/gogf/gf/contrib/trace/jaeger/v2"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gcache"
"github.com/gogf/gf/v2/os/gctx"
)
type cTrace struct{}
const (
ServiceName = "http-server-with-db"
JaegerUdpEndpoint = "localhost:6831"
)
func main() {
var ctx = gctx.New()
tp, err := jaeger.Init(ServiceName, JaegerUdpEndpoint)
if err != nil {
g.Log().Fatal(ctx, err)
}
defer tp.Shutdown(ctx)
// Set ORM cache adapter with redis.
g.DB().GetCache().SetAdapter(gcache.NewAdapterRedis(g.Redis()))
// Start HTTP server.
s := g.Server()
s.Use(ghttp.MiddlewareHandlerResponse)
s.Group("/", func(group *ghttp.RouterGroup) {
group.ALL("/user", new(cTrace))
})
s.SetPort(8199)
s.Run()
}
type InsertReq struct {
Name string `v:"required#Please input user name."`
}
type InsertRes struct {
Id int64
}
// Insert is a route handler for inserting user info into database.
func (c *cTrace) Insert(ctx context.Context, req *InsertReq) (res *InsertRes, err error) {
result, err := g.Model("user").Ctx(ctx).Insert(req)
if err != nil {
return nil, err
}
id, _ := result.LastInsertId()
res = &InsertRes{
Id: id,
}
return
}
type QueryReq struct {
Id int `v:"min:1#User id is required for querying"`
}
type QueryRes struct {
User gdb.Record
}
// Query is a route handler for querying user info. It firstly retrieves the info from redis,
// if there's nothing in the redis, it then does db select.
func (c *cTrace) Query(ctx context.Context, req *QueryReq) (res *QueryRes, err error) {
one, err := g.Model("user").Ctx(ctx).Cache(gdb.CacheOption{
Duration: 5 * time.Second,
Name: c.userCacheKey(req.Id),
Force: false,
}).WherePri(req.Id).One()
if err != nil {
return nil, err
}
res = &QueryRes{
User: one,
}
return
}
type DeleteReq struct {
Id int `v:"min:1#User id is required for deleting."`
}
type DeleteRes struct{}
// Delete is a route handler for deleting specified user info.
func (c *cTrace) Delete(ctx context.Context, req *DeleteReq) (res *DeleteRes, err error) {
_, err = g.Model("user").Ctx(ctx).Cache(gdb.CacheOption{
Duration: -1,
Name: c.userCacheKey(req.Id),
Force: false,
}).WherePri(req.Id).Delete()
if err != nil {
return nil, err
}
return
}
func (c *cTrace) userCacheKey(id int) string {
return fmt.Sprintf(`userInfo:%d`, id)
}
服務(wù)端代碼簡(jiǎn)要說(shuō)明:
jaeger.Init
?方法初始化?Jaeger
?。ORM
?和?Redis
?的鏈路跟蹤記錄。redis
?。g.DB().GetCache().SetAdapter(gcache.NewAdapterRedis(g.Redis()))
ORM
?的操作中,需要通過(guò)?Ctx
?方法將上下文變量傳遞到組件中,?orm
?組件會(huì)自動(dòng)識(shí)別當(dāng)前上下文中是否包含?Tracing
?鏈路信息,如果包含則自動(dòng)啟用鏈路跟蹤特性。ORM
?的操作中,這里使用?Cache
?方法緩存查詢(xún)結(jié)果到?redis
?中,并在刪除操作中也使用?Cache
?方法清除?redis
?中的緩存結(jié)果。啟動(dòng)服務(wù)端:
啟動(dòng)客戶(hù)端:
在?Jaeger
?上查看鏈路信息:
可以看到,這次請(qǐng)求總共產(chǎn)生了14個(gè)?span
?,其中客戶(hù)端有4個(gè)?span
?,服務(wù)端有10個(gè)?span
?,每一個(gè)?span
?代表一個(gè)鏈路節(jié)點(diǎn)。不過(guò),我們注意到,這里產(chǎn)生了3個(gè)?errors
?。我們點(diǎn)擊詳情查看什么原因呢。
我們看到好像所有的?redis
?操作都報(bào)錯(cuò)了,隨便點(diǎn)擊一個(gè)?redis
?的相關(guān)?span
?,查看一下詳情呢:
原來(lái)是?redis
?連接不上報(bào)錯(cuò)了,這樣的話(huà)所有的?orm
?緩存功能都失效了,但是可以看到并沒(méi)有影響接口邏輯,只是所有的查詢(xún)都走了數(shù)據(jù)庫(kù)。這個(gè)報(bào)錯(cuò)是因?yàn)槲冶镜赝舜蜷_(kāi)?redis server
?,我趕緊啟動(dòng)一下本地的?redis server
?,再看看效果:
再把上面的客戶(hù)端運(yùn)行一下,查看?jaeger
?:
現(xiàn)在就沒(méi)有報(bào)錯(cuò)了。
?HTTP Client&Server
?、?Logging
?組件在之前已經(jīng)介紹過(guò),因此這里我們主要關(guān)注?orm
?和?redis
?組件的鏈路跟蹤信息。
我們隨便點(diǎn)開(kāi)一個(gè)?ORM
?鏈路?Span
?,看看?Attributes/Tags
?信息:
可以看到這里的?span.kind
?是?internal
?,也就是之前介紹過(guò)的方法內(nèi)部?span
?類(lèi)型。這里很多?Tags
?在之前已經(jīng)介紹過(guò),因此這里主要介紹關(guān)于數(shù)據(jù)庫(kù)相關(guān)的?Tags
?:
Attribute/Tag
|
說(shuō)明
|
---|---|
db.type
|
數(shù)據(jù)庫(kù)連接類(lèi)型。如mysql , mssql , pgsql 等等。 |
db.link
|
數(shù)據(jù)庫(kù)連接信息。其中密碼字段被自動(dòng)隱藏。 |
db.group
|
在配置文件中的數(shù)據(jù)庫(kù)分組名稱(chēng)。 |
Event/Log
|
說(shuō)明
|
---|---|
db.execution.sql
|
執(zhí)行的具體SQL 語(yǔ)句。由于ORM底層是預(yù)處理,該語(yǔ)句為方便查看自動(dòng)拼接而成,僅供參考。 |
db.execution.type
|
執(zhí)行的SQL 語(yǔ)句類(lèi)型。常見(jiàn)為DB.ExecContext 和DB.QueryContext ,分別代表寫(xiě)操作和讀操作。 |
db.execution.cost
|
當(dāng)前 |
Attribute/Tag
|
說(shuō)明
|
---|---|
redis.host
|
Redis 連接地址。 |
redis.port
|
Redis 連接端口。 |
redis.db
|
Redis 操作db 。 |
Event/Log
|
說(shuō)明
|
---|---|
redis.execution.command
|
Redis 執(zhí)行指令。 |
redis.execution.arguments
|
Redis 執(zhí)行指令參數(shù)。 |
redis.execution.cost
|
|
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話(huà):173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: