-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
db.DB/redis.Client: Details in Address for GetAddr #53
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of informative connection logs, but I would combine that into a new function MustConnect(context.Context, *logging.Logger)
for both database.DB
and Redis.Client
. Ultimately, we do the same thing in many projects, i.e. we log where we connect and fail if it doesn't work. GetAddr()
can be removed in this PR (edit: It already is 👍). And instead of "... against database" I would write "... to database".
We could also consider technical strings, e.g. [type[+tls]://]usersname@addr/db
: mysql+tls://kubernetes@locahost:3306/kubernetes
, user@redis/5
.
The idea of a more informative connection information string was brought up in #50[0]. Currently, at least Icinga DB and Icinga Notifications are logging their connection target after startup. This information, however, is quite vague and was now extended to contain, e.g., if TLS is used, the username, the database. > INFO icingadb Connecting to database at 'mysql://icingadb@localhost:3306/icingadb' > INFO icingadb Connecting to Redis at 'redis://localhost:6380' Furthermore, the zapcore.ObjectMarshaler interface was implemented, allowing both *db.DB and *redis.Client to be used as a zap logging field, showing the address. [0] #50 (review)
006d0ec
to
8634bd8
Compare
I actually liked this approach even more. Thus, I have re-introduced the Building Icinga DB with this branch results a way more informative output:
|
Database: "db", | ||
User: "user", | ||
}, | ||
addr: "mysql://user@/var/empty/mysql.sock/db", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This demonstrates one limitation of the approach: /
can appear both in the URL syntax and in a path. The somewhat proper but ugly solution to this would be to just use net/url
where this would result in mysql://user@%2Fvar%2Fempty%2Fmysql.sock/db
.
A nicer looking alternative might be to use %q
instead of %s
for unix domain sockets, but that raises the question why make it look like an URL if it actually isn't one.
And a somewhat strange-looking alternative might be to take some inspiration from lib/pq
:
icinga-go-library/database/db.go
Lines 160 to 163 in 54b737a
// Host and port can alternatively be specified in the query string. lib/pq can't parse the connection URI | |
// if a Unix domain socket path is specified in the host part of the URI, therefore always use the query | |
// string. See also https://github.com/lib/pq/issues/796 | |
"host": {c.Host}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but that raises the question why make it look like an URL if it actually isn't one.
This was inspired by the comment above, #53 (review).
I don't know what exactly would be seen as a beautiful solution. Maybe make it more strange by prefixing a filesystem path with file://
. I just checked against the MySQL documentation and found other beauties like root@localhost?socket=%2Ftmp%2Fmysql.sock
or root@localhost?socket=(/tmp/mysql.sock)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but that raises the question why make it look like an URL if it actually isn't one.
This was inspired by the comment above, #53 (review).
With my comment I didn't mean to imply that it is absolutely necessary to create URI-like strings, but
since both MySQL and PostgreSQL use URI-like connection strings, I think it's a valid approach to create a relaxed version for logging. For sockets, I would use (/path/to/socket.sock)
or just leave it as it is.
default: | ||
return nil, unknownDbType(c.Type) | ||
} | ||
|
||
addrDescription := c.Type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see a benefit renaming addr
to addrDescription
and introducing typeAddr
. I would revert that and do the following here:
if c.TlsOptions.Enable {
addr = fmt.Sprintf("%s+tls://%s@%s/%s", c.Type, c.User, addr, c.Database)
} else {
addr = fmt.Sprintf("%s://%s@%s/%s", c.Type, c.User, addr, c.Database)
}
logger: logger, | ||
tableSemaphores: make(map[string]*semaphore.Weighted), | ||
}, nil | ||
} | ||
|
||
// GetAddr returns the database host:port or Unix socket address. | ||
// GetAddr returns the Redis connection address in a technical form. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
database
not Redis
but I would extend it anyway:
GetAddr returns the URI-like database connection string with the following syntax type[+tls]://user@host[:port]/database
.
return db.addrDescription | ||
} | ||
|
||
// MarshalLogObject implements zapcore.ObjectMarshaler, adding the database address to each log message. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would link to GetAttr
here so that it's clear which additional information is logged.
// MarshalLogObject implements zapcore.ObjectMarshaler, adding the database address to each log message. | ||
func (db *DB) MarshalLogObject(encoder zapcore.ObjectEncoder) error { | ||
encoder.AddString("database_address", db.addrDescription) | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, please add a newline before return as it improves readability.
I know that there is no specific convention or rule in Go regarding the use of newlines before return statements. Even the official Go style guide does not explicitly mention anything in this regard. But we do this in PHP as well and the majority of the code in Icinga DB and Icinga Go library already does this, so I would make this a convention for us.
Database: "db", | ||
User: "user", | ||
}, | ||
addr: "mysql://user@/var/empty/mysql.sock/db", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but that raises the question why make it look like an URL if it actually isn't one.
This was inspired by the comment above, #53 (review).
With my comment I didn't mean to imply that it is absolutely necessary to create URI-like strings, but
since both MySQL and PostgreSQL use URI-like connection strings, I think it's a valid approach to create a relaxed version for logging. For sockets, I would use (/path/to/socket.sock)
or just leave it as it is.
The idea of a more informative connection information string was brought up in #50. Currently, at least Icinga DB and Icinga Notifications are logging their connection target after startup. This information, however, is quite vague and was now extended to contain, e.g., if TLS is used, the username, the
Furthermore, the zapcore.ObjectMarshaler interface was implemented, allowing both *db.DB and *redis.Client to be used as a zap logging field, showing the address.