-
Notifications
You must be signed in to change notification settings - Fork 891
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
GODRIVER-2904 Add environment log. #1373
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.
LGTM!
x/mongo/driver/topology/topology.go
Outdated
|
||
var ( | ||
cosmosDBLog = `You appear to be connected to a CosmosDB cluster. For more information regarding feature compatibility and support please visit https://www.mongodb.com/supportability/cosmosdb` | ||
doumentDBLog = `You appear to be connected to a DoumentDB cluster. For more information regarding feature compatibility and support please visit https://www.mongodb.com/supportability/documentdb` |
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.
DoumentDB -> DocumentDB
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.
Thank you!
x/mongo/driver/topology/topology.go
Outdated
|
||
var ( | ||
cosmosDBLog = `You appear to be connected to a CosmosDB cluster. For more information regarding feature compatibility and support please visit https://www.mongodb.com/supportability/cosmosdb` | ||
documentDBLog = `You appear to be connected to a DocumentDB cluster. For more information regarding feature compatibility and support please visit https://www.mongodb.com/supportability/documentdb` |
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.
Suggest making cosmosDBLog
and documentDBLog
constants. See comments on restructuring.
x/mongo/driver/topology/topology.go
Outdated
} | ||
} | ||
|
||
func (l *hostLogger) log(host string) { |
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 think we should have a struct for logging. IIUC the only reason we do this is to maintain state so as not to repeated logs for the same host. However, it might be best to maintain this state in the code that is calling the logger, to minimize any leaking:
hostSet := map[string]bool{}
for _, host := range parsedHosts {
if h, _, err := net.SplitHostPort(host); err == nil {
host = h
}
if !hostSet[host] {
logTopoloygThirdPartyUsage(t, host)
}
hostSet[host] = true
}
x/mongo/driver/topology/topology.go
Outdated
} | ||
} | ||
|
||
func (l *hostLogger) log(host string) { |
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.
Whether we decided to use a struct or not, we should re-organize the code to match the existing "logTopology*" pattern:
func logTopologyThirdPartyUsage(topo *Topology, host string) {
thirdPartyMessages := map[string]string{
".cosmos.azure.com": cosmosDBLog,
".docdb.amazonaws.com": documentDBLog,
".docdb-elastic.amazonaws.com": documentDBLog,
}
for tphost, msg := range thirdPartyMessages {
if !strings.HasSuffix(host, tphost) {
continue
}
// Serialize the topology message to be consistent with other topology
// messages.
topo.cfg.logger.Print(logger.LevelInfo,
logger.ComponentTopology,
msg,
logger.SerializeTopology(logger.Topology{ID: topo.id, Message: msg})...)
}
}
x/mongo/driver/topology/topology.go
Outdated
} else { | ||
logger := newHostLogger(t.cfg.logger) | ||
for _, host := range parsedHosts { | ||
logger.log(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.
Before we log, we first need to check if it is appropriate to log. We should update mustLogTopologyMessage
to the following:
func mustLogTopologyMessage(topo *Topology, level logger.Level) bool {
return topo.cfg.logger != nil && topo.cfg.logger.LevelComponentEnabled(
level, logger.ComponentTopology)
}
and then wrap this block:
if mustLogTopologyMessage(t, logger.LevelInfo) {
hostSet := map[string]bool{}
for _, host := range parsedHosts {
if h, _, err := net.SplitHostPort(host); err == nil {
host = h
}
if !hostSet[host] {
logTopologyThirdPartyUsage(t, host)
}
hostSet[host] = true
}
}
The check is done on the SRV's CNAME prior to SRV lookup as per the comment. |
return err | ||
} | ||
parsedHosts := strings.Split(uri.Host, ",") | ||
if mustLogTopologyMessage(t, logger.LevelInfo) { |
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.
Optional: the only purpose of this block is to log third party connection information. It could be cleaner to create a separate function called logTopologyThirdPartyUsage
to hold all of this logic:
if mustLogTopologyMessage(t, logger.LevelInfo) {
logTopologyThirdPartyUsage(...)
}
x/mongo/driver/topology/topology.go
Outdated
} | ||
if logged, ok := hostSet[env]; ok && logged { | ||
break | ||
} else { |
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.
Optional: this else is not necessary, the logic can be written like this:
if !strings.HasSuffix(host, suffix) {
continue
}
if logged, ok := hostSet[env]; ok && logged {
break
}
hostSet[env] = true
logTopologyMessage(t, logger.LevelInfo, thirdPartyMessages[env])
x/mongo/driver/topology/topology.go
Outdated
) | ||
|
||
var ( | ||
thirdPartySuffixes = map[string]hostEnv{ |
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.
Optional: If we create a separate function (logTopologyThirdPartyUsage
), then there is no need to create package-level variables, we can nest these declarations within the logging function to give them context.
{ | ||
name: "normal", | ||
uri: "mongodb://a.mongo.cosmos.azure.com:19555/", | ||
msgs: []string{cosmosDBMsg}, |
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.
We should directly reference the cosmosDBMsg in the test, and not use a non-test constant. There are a few reasons for this:
- Test code won't change when production code is refactored. That is, if we use a constant here then refactoring the constant in the production code would break this test.
- These tests might pass if the code is wrong. Any changes to the constants will be considered valid, for instance if we accidentally append a character to the constant.
This applies to the other test cases as well.
err = topo.Connect() | ||
require.Nil(t, err, "Connect error: %v", err) | ||
|
||
require.ElementsMatch(t, tc.msgs, sink.msgs, "expected messages to be %v, got %v", tc.msgs, sink.msgs) |
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.
Should we use an assertion here? require
will stop testing if it fails. This applies to the other subtests as well.
|
||
// Note: SRV connection strings are intentionally untested, since initial | ||
// lookup responses cannot be easily mocked. | ||
func TestTopologyConstructionLogging(t *testing.T) { |
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.
Can test can be parallelized? From my testing it appears it can be.
// lookup responses cannot be easily mocked. | ||
func TestTopologyConstructionLogging(t *testing.T) { | ||
sink := &mockLogSink{} | ||
loggerOptions := options. |
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.
Optional: if these are re-defined for each subtest, then we can parallelize the subtests.
GODRIVER-2904
Summary
Log informational message client-side based on detected environment (DocumentDB or CosmosDB)
Background & Motivation
Log informational messages by examining host names added to a topology.
SRV connection strings are not tested, since initial lookup responses cannot be easily mocked.