为什么
如果你有这些问题:
- golang 官方的 mongo driver 怎么执行了没有日志输出啊
- golang mongo driver 如何记录sql,如何打印执行的命令
- 想通过日志来检查 golang mongo 调用API是否符合预期
那么这篇文章可以继续看下去。
背景
在这之前我使用 MySQL
是比较多的,后来遇到有记录用户操作日志需求,随着数据量越来越大,MySQL
有些扛不住(慢),就换成了 Mongo
,在使用Mongo
过程中,发现没法记录日志,就是无法将打印代码发起的sql
,之前使用gorm
打印execute sql
是很方便的。
在网上查了好久也没查到相关资料,就开始翻官方文档,和源码。
终于在不懈~ 打住,其实很简单,就在 ClientOptions
字段里:
// ClientOptions contains options to configure a Client instance. Each option can be set through setter functions. See
// documentation for each setter function for an explanation of the option.
type ClientOptions struct {
AppName *string
Auth *Credential
AutoEncryptionOptions *AutoEncryptionOptions
...
MaxConnecting *uint64
PoolMonitor *event.PoolMonitor
Monitor *event.CommandMonitor // 执行的命令监视器(日志)
ServerMonitor *event.ServerMonitor
...
err error
uri string
cs *connstring.ConnString
是的—— ClientOptions.Monitor
字段。
使用方法如下:
package mongolearn
import (
"context"
"fmt"
"log"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var (
mongoDsn = "mongodb://admin:[email protected]:27017"
)
// TestConnUseDb sql monitor
func TestConnWithMonitor() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// client option
var clientOpt = options.Client().ApplyURI(mongoDsn)
// log monitor
var logMonitor = event.CommandMonitor{
Started: func(ctx context.Context, startedEvent *event.CommandStartedEvent) {
log.Printf("mongo reqId:%d start on db:%s cmd:%s sql:%+v", startedEvent.RequestID, startedEvent.DatabaseName,
startedEvent.CommandName, startedEvent.Command)
},
Succeeded: func(ctx context.Context, succeededEvent *event.CommandSucceededEvent) {
log.Printf("mongo reqId:%d exec cmd:%s success duration %d ns", succeededEvent.RequestID,
succeededEvent.CommandName, succeededEvent.DurationNanos)
},
Failed: func(ctx context.Context, failedEvent *event.CommandFailedEvent) {
log.Printf("mongo reqId:%d exec cmd:%s failed duration %d ns", failedEvent.RequestID,
failedEvent.CommandName, failedEvent.DurationNanos)
},
}
// cmd monitor set
clientOpt.SetMonitor(&logMonitor)
client, err := mongo.Connect(ctx, clientOpt)
if nil != err {
fmt.Printf("mongo connect err %v\n", err)
} else {
fmt.Printf("mongo connect success~\n")
defer func() {
if err = client.Disconnect(ctx); err != nil {
panic(err)
}
}()
}
// update test
if re, err := client.Database("test").Collection("test").UpdateOne(ctx, bson.M{"name": "cc"}, bson.M{"$set": bson.M{"age": 12}}); err != nil {
log.Printf("%v", err)
} else {
log.Printf("mongo update one re %+v", re)
}
}
输出结果
mongo connect success~
2023/08/20 13:22:43 mongo reqId:6 start on db:test cmd:update sql:{"update": "test","ordered": true,"lsid": {"id": {"$binary":{"base64":"qfrrzSt7SkCN5ChY04/T5A==","subType":"04"}}},"$db": "test","updates": [{"q": {"name": "cc"},"u": {"$set": {"age": {"$numberInt":"12"}}}}]}
2023/08/20 13:22:43 mongo reqId:6 exec cmd:update success duration 44489114 ns
2023/08/20 13:22:43 mongo update one re &{MatchedCount:0 ModifiedCount:0 UpsertedCount:0 UpsertedID:}
# 下面是断开 mongo 时触发的命令
2023/08/20 13:22:43 mongo reqId:7 start on db:admin cmd:endSessions sql:{"endSessions": [{"id": {"$binary":{"base64":"qfrrzSt7SkCN5ChY04/T5A==","subType":"04"}}}],"$db": "admin"}
2023/08/20 13:22:43 mongo reqId:7 exec cmd:endSessions success duration 58037162 ns
通过以上日志可以看到,mongo
的 monitor
按照 Started
, Succeeded
顺序记录,最后才会执行函数外的 日志 。
结束
我看网上资料少,很多小伙伴都不知道,特此写一篇小文记录下。