-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
gcp/observability: Add support for Environment Variable GRPC_CONFIG_OBSERVABILITY_JSON #5525
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.
Looks really good; just some nits (mostly in the tests).
if err := validateFilters(&config); err != nil { | ||
return nil, fmt.Errorf("error parsing observability config: %v", err) | ||
} | ||
if config.GlobalTraceSamplingRate > 1 || config.GlobalTraceSamplingRate < 0 { | ||
return nil, fmt.Errorf("error parsing observability config: invalid global trace sampling rate %v", config.GlobalTraceSamplingRate) | ||
} | ||
logger.Infof("Parsed ObservabilityConfig: %+v", &config) |
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.
None of this is technically unmarshalling. Move this out and make a different function? Or name this unmarshalAndVerifyConfig
?
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.
Good point, I like second option. The reason it was pulled into a helper was needed twice for both env vars, and I don't want to add another helper function/callsite.
gcp/observability/config.go
Outdated
if fileSystemPath := os.Getenv(envObservabilityConfigJSON); fileSystemPath != "" { | ||
content, err := os.ReadFile(fileSystemPath) | ||
if err != nil { | ||
return nil, fmt.Errorf("error reading file from env var %v: %v", envObservabilityConfigJSON, err) |
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.
Print fileSystemPath
? Also avoid shorthand/abbreviations in user-visible error messages ("env var" -> "environment variable").
"error reading observability configuration file %q: %v", fileSystemPath, err"
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.
Noted. Switched to your defined error string.
config := &configpb.ObservabilityConfig{ | ||
EnableCloudLogging: true, | ||
DestinationProjectId: "fake", | ||
LogFilters: []*configpb.ObservabilityConfig_LogFilter{ | ||
{ | ||
Pattern: "*", | ||
HeaderBytes: infinitySizeBytes, | ||
MessageBytes: infinitySizeBytes, | ||
}, | ||
}, | ||
} |
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.
Nit: it would be nicer to test this using a raw JSON string instead.
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.
Done.
t.Fatalf("failed to convert config to JSON: %v", err) | ||
} | ||
|
||
configJSONFile, err := os.Create("/tmp/configJSON") |
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.
Use a function that creates a random, non-existent temp file rather than potentially overwriting an existing one owned by the user. Also that allows running multiple times concurrently.
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.
Thanks for the suggestion. Done (created a helper function for both tests to call).
|
||
// TestBothConfigEnvVarsSet tests the scenario where both configuration | ||
// environment variables are set. The file system environment variable should | ||
// take precedence, and and error should return in the case of the file system |
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.
and _an_ error
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.
Ah whoops. Switched.
invalidConfig := &configpb.ObservabilityConfig{ | ||
EnableCloudLogging: true, | ||
DestinationProjectId: "fake", | ||
LogFilters: []*configpb.ObservabilityConfig_LogFilter{ | ||
{ | ||
Pattern: ":-)", | ||
}, | ||
{ | ||
Pattern: "*", | ||
}, | ||
}, | ||
} |
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.
As above
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.
Switched to a raw JSON string.
} | ||
os.Setenv(envObservabilityConfigJSON, "/tmp/configJSON") | ||
|
||
if err := Start(context.Background()); err != 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.
Use a context with a timeout?
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.
Switched.
BTW the tests are failing:
|
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.
Thanks for the comments :D!
if err := validateFilters(&config); err != nil { | ||
return nil, fmt.Errorf("error parsing observability config: %v", err) | ||
} | ||
if config.GlobalTraceSamplingRate > 1 || config.GlobalTraceSamplingRate < 0 { | ||
return nil, fmt.Errorf("error parsing observability config: invalid global trace sampling rate %v", config.GlobalTraceSamplingRate) | ||
} | ||
logger.Infof("Parsed ObservabilityConfig: %+v", &config) |
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.
Good point, I like second option. The reason it was pulled into a helper was needed twice for both env vars, and I don't want to add another helper function/callsite.
gcp/observability/config.go
Outdated
if fileSystemPath := os.Getenv(envObservabilityConfigJSON); fileSystemPath != "" { | ||
content, err := os.ReadFile(fileSystemPath) | ||
if err != nil { | ||
return nil, fmt.Errorf("error reading file from env var %v: %v", envObservabilityConfigJSON, err) |
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.
Noted. Switched to your defined error string.
|
||
// TestBothConfigEnvVarsSet tests the scenario where both configuration | ||
// environment variables are set. The file system environment variable should | ||
// take precedence, and and error should return in the case of the file system |
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.
Ah whoops. Switched.
} | ||
os.Setenv(envObservabilityConfigJSON, "/tmp/configJSON") | ||
|
||
if err := Start(context.Background()); err != 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.
Switched.
t.Fatalf("failed to convert config to JSON: %v", err) | ||
} | ||
|
||
configJSONFile, err := os.Create("/tmp/configJSON") |
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.
Thanks for the suggestion. Done (created a helper function for both tests to call).
config := &configpb.ObservabilityConfig{ | ||
EnableCloudLogging: true, | ||
DestinationProjectId: "fake", | ||
LogFilters: []*configpb.ObservabilityConfig_LogFilter{ | ||
{ | ||
Pattern: "*", | ||
HeaderBytes: infinitySizeBytes, | ||
MessageBytes: infinitySizeBytes, | ||
}, | ||
}, | ||
} |
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.
Done.
invalidConfig := &configpb.ObservabilityConfig{ | ||
EnableCloudLogging: true, | ||
DestinationProjectId: "fake", | ||
LogFilters: []*configpb.ObservabilityConfig_LogFilter{ | ||
{ | ||
Pattern: ":-)", | ||
}, | ||
{ | ||
Pattern: "*", | ||
}, | ||
}, | ||
} |
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.
Switched to a raw JSON string.
gcp/observability/config.go
Outdated
// into it's protobuf format. | ||
func unmarshalConfig(rawJSON json.RawMessage) (*configpb.ObservabilityConfig, error) { | ||
// unmarshalAndVerifyConfig unmarshals a json string representing an | ||
// observability config into it's protobuf format, and also verifies the |
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.
*its. '
!= possession
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.
Switched.
} | ||
os.Setenv(envObservabilityConfigJSON, "/tmp/configJSON") | ||
os.Setenv(envObservabilityConfigJSON, configJSONFile.Name()) | ||
return configJSONFile, nil /// do you even need to return this file if you're already closing it here? |
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 delete it after the test?
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.
Yeah good point. Stored this returned in a local variable at call sites and defered the Close().
// GRPC_CONFIG_OBSERVABILITY_JSON environment variable, whose value represents a | ||
// file path pointing to a JSON encoded config. | ||
func (s) TestJSONEnvVarSet(t *testing.T) { | ||
configJSON := json.RawMessage(`{ |
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.
Pass to createTmpConfigFile
as a string instead of a json.RawMessage to avoid the cast at every callsite?
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.
Switched.
This PR adds support for the Environment Variable GRPC_CONFIG_OBSERVABILITY_JSON, which configures observability through a file at a path specified by the value of this Environment Variable (see private preview 2 document: go/grpc-observability-ug-2). The precedence ordering of this environment variable taking precedence over GRPC_CONFIG_OBSERVABILITY is based on the grpc-java implementation to keep it consistent across languages, and not officially defined in the design document.
RELEASE NOTES: