Do you think it could be useful to use log.Logger and allow the ability to set a custom logger instead of using log.Println? Execv and friends are nice, but it would be great if those logs could be sent somewhere other than STDOUT.
You can get the standard logger to point to any io.Writer by calling log.SetOutput. Hopefully this will suffice for your needs.
Obviously, sqlx isn't a logging package. Sadly, the log package is rather simple and not really easily extended by custom loggers.
I'll have to look into what other packages do for logging. I feel like I see the generic standard logger in use pretty often. There are locking issues with trying to use multiple loggers on a single output file, so if I abandon the standard logger, that might lead to some unpredictable results for some people. In the worst case, they might start to lose messages they are currently getting.
Oh wow, I didn't know about log.SetOutput, I don't know how I missed that. Thanks!
It seems like using log.Logger and allowing custom loggers would be the right way to do it, but I don't know for sure. For example, see the log/syslog package: http://golang.org/pkg/log/syslog/
The logging variants are no longer part of sqlx because I felt their convenience was not worth the extra noise in the API documentation. They are trivially implemented in any codebase. Because of that this is not really an issue anymore.
I really like the way logrus is handling this.
Hooks can be registered, and will receive a copy of the log entry. Maybe Exec, Select, etc. could act the same. Adding logging / performance measurement would be easily achived, without creating a new type and wrap all the methods (which I has to do). Wrapping is weak and doesn't support API changes very well :(
(weak -> New methods are not wrapped until we write the code)
(changes -> Need to update all wrappers where API changed)
Just thought I'd chime in with interesting idea I saw suggested on StackOverflow: https://stackoverflow.com/a/33042034/718180
sqlx has a very interesting abstraction in the form of the following interfaces:
They are used all through the library as the interfaces representing the functionality of using strings as SQL queries.
...
So if you are willing not to use the DB type directly but instead use the underlying free functions of the library, you can use the following structure to wrap your db into objects that perform logging:
type QueryLogger struct { queryer sqlx.Queryer logger *log.Logger } func (p *QueryLogger) Query(query string, args ...interface{}) (*sql.Rows, error) { p.logger.Print(query, args...) return p.queryer.Query(query, args...) } func (p *QueryLogger) Queryx(query string, args ...interface{}) (*Rows, error) { p.logger.Print(query, args...) return p.queryer.Queryx(query, args...) } func (p *QueryLogger) QueryRowx(query string, args ...interface{}) *Row { p.logger.Print(query, args...) return p.queryer.QueryRowx(query, args...) }And when connecting to your database:
db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable") if err != nil { log.Fatalln(err) } ql := &QueryLogger{db, yourLogger} sqlx.Select(ql, &people, "SELECT * FROM person ORDER BY first_name ASC")
How does one 'trivially implement this in any codebase'? Where is the hook to get at logging every query?
Most helpful comment
Just thought I'd chime in with interesting idea I saw suggested on StackOverflow: https://stackoverflow.com/a/33042034/718180