preface
To facilitate troubleshooting, record the mapping between the current request information and the SQL information that is currently executed. The recorded SQL information includes:
- The current time of SQL execution;
- The address and line number of the file to execute the SQL;
- The time spent executing SQL;
- The number of rows affected by SQL execution;
- SQL statement executed;
The database component uses GORM.
Train of thought
- 1, before executing SQL, set the start execution time (used to calculate the execution time);
- 2, after the execution of SQL, first, get the context of the current request, why get the context, because you need to get the information from the context of the request, second, get the time before the execution of SQL, used to calculate the execution time, third, get the execution of SQL information, and then set the data to
Trace
,Trace
Is the link packet in the project, which will be introduced later in the article;
Callbacks and Context are only available in GORM V2. The package that needs to be imported is GORM. IO/GORM.
Demo code
Context is passed using the WithContext() method provided by GORM V2.
func (u *userRepo) getUserByID(ctx core.Context, id uint) (*user_model.UserDemo, error) { data := new(user_model.UserDemo) err := u.db.GetDbR().WithContext(ctx).First(data, id).Error if err ! = nil { return nil, errors.Wrap(err, "[user_demo] get user data err") } return data, nil }Copy the code
Write CallBacks plug-in code, GORM Plugin interface writing is very simple, only need to implement two methods.
// Plugin GORM plugin interface
type Plugin interface {
Name() string
Initialize(*DB) error
}
Copy the code
Here is the plugin code I wrote:
type TracePlugin struct{} func (op *TracePlugin) Name() string { return "tracePlugin" } func (op *TracePlugin) Initialize(db * gorm.db) (err Error) {// Before _ = db.Callback().Create().Before("gorm:before_create").Register(callBackBeforeName, before) _ = db.Callback().Query().Before("gorm:query").Register(callBackBeforeName, before) _ = db.Callback().Delete().Before("gorm:before_delete").Register(callBackBeforeName, before) _ = db.Callback().Update().Before("gorm:setup_reflect_value").Register(callBackBeforeName, before) _ = db.Callback().Row().Before("gorm:row").Register(callBackBeforeName, before) _ = db.Callback().Raw().Before("gorm:raw").Register(callBackBeforeName, After_create ().after ("gorm:after_create").register (callBackAfterName, after) _ = db.Callback().Query().After("gorm:after_query").Register(callBackAfterName, after) _ = db.Callback().Delete().After("gorm:after_delete").Register(callBackAfterName, after) _ = db.Callback().Update().After("gorm:after_update").Register(callBackAfterName, after) _ = db.Callback().Row().After("gorm:row").Register(callBackAfterName, after) _ = db.Callback().Raw().After("gorm:raw").Register(callBackAfterName, after) return } var _ gorm.Plugin = &TracePlugin{} func before(db *gorm.DB) { db.InstanceSet(startTime, time.Now()) return } func after(db *gorm.DB) { _ctx := db.Statement.Context ctx, ok := _ctx.(core.Context) if ! ok { return } _ts, isExist := db.InstanceGet(startTime) if ! isExist { return } ts, ok := _ts.(time.Time) if ! ok { return } sql := db.Dialector.Explain(db.Statement.SQL.String(), db.Statement.Vars...) sqlInfo := new(trace.SQL) sqlInfo.Timestamp = time_parse.CSTLayoutString() sqlInfo.SQL = sql sqlInfo.Stack = utils.FileWithLineNum() sqlInfo.Rows = db.Statement.RowsAffected sqlInfo.CostSeconds = time.Since(ts).Seconds() ctx.Trace().AppendSQL(sqlInfo) return }Copy the code
Finally, use this plugin when db is connected:
Db.use (&traceplugin {})Copy the code
The effect
summary
This is part of the trace package written to record this information:
- Trace_id can be set
- Request information can be set
- Response information can be set
- Support setting third_party_requests three-party request information
- Supports setting the DEBUgs to print debugging information
- SQLS can be set to execute SQL information
- Cost_seconds execution duration can be recorded
The above code is in the Go-Gin-API project at github.com/xinliangnot…