first commit
This commit is contained in:
81
pkg/trace/README.md
Normal file
81
pkg/trace/README.md
Normal file
@ -0,0 +1,81 @@
|
||||
## trace
|
||||
|
||||
一个用于开发调试的辅助工具。
|
||||
|
||||
可以实时显示当前页面的操作的请求信息、运行情况、SQL执行、错误提示等。
|
||||
|
||||
- `trace.go` 主入口文件;
|
||||
- `dialog.go` 处理 third_party_requests 记录;
|
||||
- `debug.go` 处理 debug 记录;
|
||||
|
||||
#### 数据格式
|
||||
|
||||
##### trace_id
|
||||
|
||||
当前 trace 的 ID,例如:938ff86be98439c6c1a7,便于搜索使用。
|
||||
|
||||
##### request
|
||||
|
||||
请求信息,会包括:
|
||||
|
||||
- ttl 请求超时时间,例如:2s 或 un-limit
|
||||
- method 请求方式,例如:GET 或 POST
|
||||
- decoded_url 请求地址
|
||||
- header 请求头信息
|
||||
- body 请求体信息
|
||||
|
||||
##### response
|
||||
|
||||
- header 响应头信息
|
||||
- body 响应提信息
|
||||
- business_code 业务码,例如:10010
|
||||
- business_code_msg 业务码信息,例如:签名错误
|
||||
- http_code HTTP 状态码,例如:200
|
||||
- http_code_msg HTTP 状态码信息,例如:OK
|
||||
- cost_seconds 耗费时长:单位秒,比如 0.001105661
|
||||
|
||||
##### third_party_requests
|
||||
|
||||
每一个第三方 http 请求都会生成如下的一组数据,多个请求会生成多组数据。
|
||||
|
||||
- request,同上 request 结构一致
|
||||
- response,同上 response 结构一致
|
||||
- success,是否成功,true 或 false
|
||||
- cost_seconds,耗费时长:单位秒
|
||||
|
||||
注意:response 中的 business_code、business_code_msg 为空,因为各个第三方返回结构不同,这两个字段为空。
|
||||
|
||||
##### sqls
|
||||
|
||||
执行的 SQL 信息,多个 SQL 会记录多组数据。
|
||||
|
||||
- timestamp,时间,格式:2006-01-02 15:04:05
|
||||
- stack,文件地址和行号
|
||||
- cost_seconds,执行时长,单位:秒
|
||||
- sql,SQL 语句
|
||||
- rows_affected,影响行数
|
||||
|
||||
##### debugs
|
||||
|
||||
- key 打印的标示
|
||||
- value 打印的值
|
||||
|
||||
```cassandraql
|
||||
// 调试时,使用这个方法:
|
||||
p.Print("key", "value", p.WithTrace(c.Trace()))
|
||||
```
|
||||
|
||||
只有参数中增加了 `p.WithTrace(c.Trace())`,才会记录到 `debugs` 中。
|
||||
|
||||
##### success
|
||||
|
||||
是否成功,true 或 false
|
||||
|
||||
```cassandraql
|
||||
success = !ctx.IsAborted() && ctx.Writer.Status() == http.StatusOK
|
||||
```
|
||||
|
||||
##### cost_seconds
|
||||
|
||||
耗费时长:单位秒,比如 0.001105661
|
||||
|
7
pkg/trace/debug.go
Normal file
7
pkg/trace/debug.go
Normal file
@ -0,0 +1,7 @@
|
||||
package trace
|
||||
|
||||
type Debug struct {
|
||||
Key string `json:"key"` // 标示
|
||||
Value any `json:"value"` // 值
|
||||
CostSeconds float64 `json:"cost_seconds"` // 执行时间(单位秒)
|
||||
}
|
32
pkg/trace/dialog.go
Normal file
32
pkg/trace/dialog.go
Normal file
@ -0,0 +1,32 @@
|
||||
package trace
|
||||
|
||||
import "sync"
|
||||
|
||||
var _ D = (*Dialog)(nil)
|
||||
|
||||
type D interface {
|
||||
i()
|
||||
AppendResponse(resp *Response)
|
||||
}
|
||||
|
||||
// Dialog 内部调用其它方接口的会话信息;失败时会有retry操作,所以 response 会有多次。
|
||||
type Dialog struct {
|
||||
mux sync.Mutex
|
||||
Request *Request `json:"request"` // 请求信息
|
||||
Responses []*Response `json:"responses"` // 返回信息
|
||||
Success bool `json:"success"` // 是否成功,true 或 false
|
||||
CostSeconds float64 `json:"cost_seconds"` // 执行时长(单位秒)
|
||||
}
|
||||
|
||||
func (d *Dialog) i() {}
|
||||
|
||||
// AppendResponse 按转的追加response信息
|
||||
func (d *Dialog) AppendResponse(resp *Response) {
|
||||
if resp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
d.mux.Lock()
|
||||
d.Responses = append(d.Responses, resp)
|
||||
d.mux.Unlock()
|
||||
}
|
17
pkg/trace/grpc.go
Normal file
17
pkg/trace/grpc.go
Normal file
@ -0,0 +1,17 @@
|
||||
package trace
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
type Grpc struct {
|
||||
Timestamp string `json:"timestamp"` // 时间,格式:2006-01-02 15:04:05
|
||||
Addr string `json:"addr"` // 地址
|
||||
Method string `json:"method"` // 操作方法
|
||||
Meta metadata.MD `json:"meta"` // Mate
|
||||
Request map[string]any `json:"request"` // 请求信息
|
||||
Response map[string]any `json:"response"` // 返回信息
|
||||
CostSeconds float64 `json:"cost_seconds"` // 执行时间(单位秒)
|
||||
Code string `json:"err_code,omitempty"` // 错误码
|
||||
Message string `json:"err_message,omitempty"` // 错误信息
|
||||
}
|
10
pkg/trace/redis.go
Normal file
10
pkg/trace/redis.go
Normal file
@ -0,0 +1,10 @@
|
||||
package trace
|
||||
|
||||
type Redis struct {
|
||||
Timestamp string `json:"timestamp"` // 时间,格式:2006-01-02 15:04:05
|
||||
Handle string `json:"handle"` // 操作,SET/GET 等
|
||||
Key string `json:"key"` // Key
|
||||
Value string `json:"value,omitempty"` // Value
|
||||
TTL float64 `json:"ttl,omitempty"` // 超时时长(单位分)
|
||||
CostSeconds float64 `json:"cost_seconds"` // 执行时间(单位秒)
|
||||
}
|
9
pkg/trace/sql.go
Normal file
9
pkg/trace/sql.go
Normal file
@ -0,0 +1,9 @@
|
||||
package trace
|
||||
|
||||
type SQL struct {
|
||||
Timestamp string `json:"timestamp"` // 时间,格式:2006-01-02 15:04:05
|
||||
Stack string `json:"stack"` // 文件地址和行号
|
||||
SQL string `json:"sql"` // SQL 语句
|
||||
Rows int64 `json:"rows_affected"` // 影响行数
|
||||
CostSeconds float64 `json:"cost_seconds"` // 执行时长(单位秒)
|
||||
}
|
154
pkg/trace/trace.go
Normal file
154
pkg/trace/trace.go
Normal file
@ -0,0 +1,154 @@
|
||||
package trace
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const Header = "X-TRACE-ID"
|
||||
|
||||
var _ T = (*Trace)(nil)
|
||||
|
||||
type T interface {
|
||||
i()
|
||||
ID() string
|
||||
WithRequest(req *Request) *Trace
|
||||
WithResponse(resp *Response) *Trace
|
||||
AppendDialog(dialog *Dialog) *Trace
|
||||
AppendDebug(debug *Debug) *Trace
|
||||
AppendSQL(sql *SQL) *Trace
|
||||
AppendRedis(redis *Redis) *Trace
|
||||
AppendGRPC(grpc *Grpc) *Trace
|
||||
}
|
||||
|
||||
// Trace 记录的参数
|
||||
type Trace struct {
|
||||
mux sync.Mutex
|
||||
Identifier string `json:"trace_id"` // 链路ID
|
||||
Request *Request `json:"request"` // 请求信息
|
||||
Response *Response `json:"response"` // 返回信息
|
||||
ThirdPartyRequests []*Dialog `json:"third_party_requests,omitempty"` // 调用第三方接口的信息
|
||||
Debugs []*Debug `json:"debugs,omitempty"` // 调试信息
|
||||
SQLs []*SQL `json:"sqls,omitempty"` // 执行的 SQL 信息
|
||||
Redis []*Redis `json:"redis,omitempty"` // 执行的 Redis 信息
|
||||
GRPCs []*Grpc `json:"grpc,omitempty"` // 执行的 gRPC 信息
|
||||
Success bool `json:"success"` // 请求结果 true or false
|
||||
CostSeconds float64 `json:"cost_seconds"` // 执行时长(单位秒)
|
||||
}
|
||||
|
||||
// Request 请求信息
|
||||
type Request struct {
|
||||
TTL string `json:"ttl,omitempty"` // 请求超时时间
|
||||
Method string `json:"method"` // 请求方式
|
||||
DecodedURL string `json:"decoded_url"` // 请求地址
|
||||
Header any `json:"header"` // 请求 Header 信息
|
||||
Body any `json:"body"` // 请求 Body 信息
|
||||
}
|
||||
|
||||
// Response 响应信息
|
||||
type Response struct {
|
||||
Header any `json:"header"` // Header 信息
|
||||
Body any `json:"body"` // Body 信息
|
||||
BusinessCode int `json:"business_code,omitempty"` // 业务码
|
||||
BusinessCodeMsg string `json:"business_code_msg,omitempty"` // 提示信息
|
||||
HttpCode int `json:"http_code"` // HTTP 状态码
|
||||
HttpCodeMsg string `json:"http_code_msg"` // HTTP 状态码信息
|
||||
CostSeconds float64 `json:"cost_seconds"` // 执行时间(单位秒)
|
||||
}
|
||||
|
||||
func New(id string) *Trace {
|
||||
if id == "" {
|
||||
buf := make([]byte, 10)
|
||||
_, _ = rand.Read(buf)
|
||||
id = hex.EncodeToString(buf)
|
||||
}
|
||||
|
||||
return &Trace{
|
||||
Identifier: id,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Trace) i() {}
|
||||
|
||||
// ID 唯一标识符
|
||||
func (t *Trace) ID() string {
|
||||
return t.Identifier
|
||||
}
|
||||
|
||||
// WithRequest 设置request
|
||||
func (t *Trace) WithRequest(req *Request) *Trace {
|
||||
t.Request = req
|
||||
return t
|
||||
}
|
||||
|
||||
// WithResponse 设置response
|
||||
func (t *Trace) WithResponse(resp *Response) *Trace {
|
||||
t.Response = resp
|
||||
return t
|
||||
}
|
||||
|
||||
// AppendDialog 安全的追加内部调用过程dialog
|
||||
func (t *Trace) AppendDialog(dialog *Dialog) *Trace {
|
||||
if dialog == nil {
|
||||
return t
|
||||
}
|
||||
|
||||
t.mux.Lock()
|
||||
defer t.mux.Unlock()
|
||||
|
||||
t.ThirdPartyRequests = append(t.ThirdPartyRequests, dialog)
|
||||
return t
|
||||
}
|
||||
|
||||
// AppendDebug 追加 debug
|
||||
func (t *Trace) AppendDebug(debug *Debug) *Trace {
|
||||
if debug == nil {
|
||||
return t
|
||||
}
|
||||
|
||||
t.mux.Lock()
|
||||
defer t.mux.Unlock()
|
||||
|
||||
t.Debugs = append(t.Debugs, debug)
|
||||
return t
|
||||
}
|
||||
|
||||
// AppendSQL 追加 SQL
|
||||
func (t *Trace) AppendSQL(sql *SQL) *Trace {
|
||||
if sql == nil {
|
||||
return t
|
||||
}
|
||||
|
||||
t.mux.Lock()
|
||||
defer t.mux.Unlock()
|
||||
|
||||
t.SQLs = append(t.SQLs, sql)
|
||||
return t
|
||||
}
|
||||
|
||||
// AppendRedis 追加 Redis
|
||||
func (t *Trace) AppendRedis(redis *Redis) *Trace {
|
||||
if redis == nil {
|
||||
return t
|
||||
}
|
||||
|
||||
t.mux.Lock()
|
||||
defer t.mux.Unlock()
|
||||
|
||||
t.Redis = append(t.Redis, redis)
|
||||
return t
|
||||
}
|
||||
|
||||
// AppendGRPC 追加 gRPC 调用信息
|
||||
func (t *Trace) AppendGRPC(grpc *Grpc) *Trace {
|
||||
if grpc == nil {
|
||||
return t
|
||||
}
|
||||
|
||||
t.mux.Lock()
|
||||
defer t.mux.Unlock()
|
||||
|
||||
t.GRPCs = append(t.GRPCs, grpc)
|
||||
return t
|
||||
}
|
Reference in New Issue
Block a user