英文:
How to log queries to database drivers?
问题
我正在尝试用Go语言编写一个简单的数据库应用程序,它可以访问多个数据服务器,包括MySQL、MSSQL和SqlLite3。我正在使用"database/sql"包来访问它们。
db, err := sql.Open(driver, dataSourceName)
result, err := db.Exec(
"INSERT INTO users (name, age) VALUES (?, ?)",
"gopher",
27,
)
我需要将SQL查询记录到各个服务器上以进行调试和审计。我该如何实现这个功能?
英文:
I am trying to write a simple Database application in go which access multiple data servers, some MySQL, MSSQL and SqlLite3.
I am using the "database/sql" package to access them.
db, err := sql.Open(driver, dataSourceName)
result, err := db.Exec(
"INSERT INTO users (name, age) VALUES (?, ?)",
"gopher",
27,
)
I need to log the SQL queries to the individual servers for debugging and auditing.
How can I achieve that?
答案1
得分: 1
假设您不想使用服务器的日志记录功能,显而易见的解决方案是将所有查询记录下来。
db, err := sql.Open(driver, dataSourceName)
log.Println(dataSourceName, "INSERT INTO users (name, age) VALUES (?, ?)", "gopher", 27)
result, err := db.Exec(
"INSERT INTO users (name, age) VALUES (?, ?)",
"gopher",
27,
)
这是您问题的基本解决方案。您可以通过以下多种方式进行改进:
- 为您的查询创建一个专门的
log.Logger
,以便将其定向到特定的输出目标。 - 在一个特殊的结构中包装上述的
log.Logger
和sql.DB
对象,以在执行查询时记录它们。
以下是一个简单的示例结构:
type DB struct {
db *sql.DB
dsn string
log *log.Logger
}
func NewDB(driver, dsn string, log *log.Logger) (*DB, error) {
db, err := sql.Open(driver, dsn)
if err != nil {
return nil, err
}
return &DB{
db: db,
dsn: dsn,
log: log,
}, nil
}
func (d DB) Exec(query string, args ...interface{}) (sql.Result, error) {
d.log.Println(d.dsn, query, args)
return d.db.Exec(query, args...)
}
下面是如何使用它的示例:
l := log.New(os.Stdout, "[sql]", log.LstdFlags)
db, _ := NewDB(driver, dataSourceName, l)
result, _ := db.Exec(
"INSERT INTO users (name, age) VALUES (?, ?)",
"gopher",
27,
)
显然,您可以通过添加错误报告、查询持续时间等来进一步完善这个设计。
英文:
Assuming that you don't want to use the servers logging facilities, the obvious solution would be to simply log all queries as they are made.
db, err := sql.Open(driver, dataSourceName)
log.Println(dataSourceName, "INSERT INTO users (name, age) VALUES (?, ?)", "gopher", 27)
result, err := db.Exec(
"INSERT INTO users (name, age) VALUES (?, ?)",
"gopher",
27,
)
This is the basic solution for your problem. You can refine it in multiple ways:
- Create a
log.Logger
exclusively for your queries, so you can direct it to a particular output destination - Wrap the said
log.Logger
and thesql.DB
objects in a special struct that will log queries as they are done
Here is a rough example of the said struct:
type DB struct {
db *sql.DB
dsn string
log *log.Logger
}
func NewDB(driver, dsn string, log *log.Logger) (*DB, error) {
db, err := sql.Open(driver, dsn)
if err != nil {
return nil, err
}
return &DB {
db: db,
dsn: dsn,
log: log,
}
}
func (d DB) Exec(query string, args ...interface{}) (sql.Result, err) {
d.log.Println(dsn, query, args)
return d.db.Exec(query, args...)
}
And how you would use it:
l := log.New(os.Stdout, "[sql]", log.LstdFlags)
db, _ := NewDB(driver, dataSourceName, l)
result, _ := db.Exec(
"INSERT INTO users (name, age) VALUES (?, ?)",
"gopher",
27,
)
Obviously, you can refined this design again, by adding error reporting, duration of the queries, etc.
答案2
得分: 0
现在有一种解决方案,可以在不使用添加日志的包装器的情况下解决这个问题。
sqldblogger 可以在不改变现有 sql.DB
代码的情况下实现这一点。
英文:
There is now a solution for that without having to wrap sql.DB
with a wrapper that adds the logging.
sqldblogger facilitates this without needing to change existing sql.DB
code.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论