Skip to content

Do not log in log library#1364

Closed
bobcatfish wants to merge 1 commit intoknative:masterfrom
bobcatfish:logging_in_log_lib
Closed

Do not log in log library#1364
bobcatfish wants to merge 1 commit intoknative:masterfrom
bobcatfish:logging_in_log_lib

Conversation

@bobcatfish
Copy link
Copy Markdown
Contributor

Okay this is a lot repeated code, but hear me out! When you log in
a library, it means the caller has no control over whether those
logs are emitted or not - case in point, the e2e tests are using this
library, and now they dump the json config and log level at the
beginning of every test, which we don't want and can't control.

This commit changes the logging lib such that it's the caller's
responsibility to decide whether to log or not.

  • Also open to ideas that involve less code duplication, e.g. a(nother) wrapper that logs, such that the interface includes functions which log and functions which do not log.)
  • Another option is to have the e2e tests use zap directly instead of using the knative logging lib.)

This is what the test output looks like before this change, in verbose mode:
image

In the default mode:
image

Proposed Changes

  • Remove code that actual logs from the log library
  • Update users of the log library to log info about initializing the logger
NONE

@google-prow-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: bobcatfish
To fully approve this pull request, please assign additional approvers.
We suggest the following additional approver: mattmoor

Assign the PR to them by writing /assign @mattmoor in a comment when ready.

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@google-prow-robot google-prow-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Jun 26, 2018
@bobcatfish
Copy link
Copy Markdown
Contributor Author

pkg/logging/config.go | 77.8% | 76.0% | -1.8

squinty eyes

Comment thread cmd/activator/main.go Outdated
proxy.ServeHTTP(w, r)
}

func _initializeLogging() *zap.SugaredLogger {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest dropping the underscore since it's not really a style I see in go

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

face palm my bad!

Comment thread pkg/logging/config.go Outdated
logger.Error("Failed to parse the logging config. Falling back to default logger.", zap.Error(err), zap.String(logkey.JSONConfig, configJSON))
return logger.Sugar()
errStr := fmt.Sprintf("Failed to parse the logging config. Falling back to default logger. Error: %s. Config: %s", err, configJSON)
return logger.Sugar(), errors.New(errStr)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fmt.Errorf will combine your fmt.Sprintf and errors.New

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ooo nice!

Comment thread cmd/activator/main.go Outdated

func _initializeLogging() *zap.SugaredLogger {
configJSON, levelOverride := logging.LoggerDefaultConfigMap("loglevel.activator")
genericLogger, err := logging.NewLogger(configJSON, levelOverride)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could simplify the interface a bit more so we only make one call to the logging pkg to instantiate a configured logger.

ie.

logger, err := logging.NewLoggerFromConfig("loglevel.activator")

then maybe _initializeLogging is small enough to inline it into main() ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to change the assumption this package makes about the config being mounted at /etc/config-logging as well. @mdemirhan thoughts?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Context: #1351

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am all for removing the dependency on the etc/config-logging. It was meant as a helper to reduce the copy/paste between all main.go files.

@bobcatfish The changes look good to me. The duplication hurts the eyes, but if it is going to make things better for tests, I am all for it. Can the new "initializeLogging" not be generalized enough so that we avoid duplication? Alternatively, passing a "do not log" flag to the existing NewLoggerFromXXX method could achieve the same thing and tests can use that flag when initializing its loggers.

@evankanderson
Copy link
Copy Markdown
Member

/assign @dprotaso
/assign @mattmoor

@bobcatfish bobcatfish force-pushed the logging_in_log_lib branch 3 times, most recently from e7f10da to 4cd6bc4 Compare June 27, 2018 22:56
Comment thread test/e2e_flags.go Outdated
}
defer logger.Sync()
return logger
>>>>>>> Do not log in log library
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ho boy 😅

@bobcatfish bobcatfish force-pushed the logging_in_log_lib branch from 4cd6bc4 to 441ef04 Compare June 27, 2018 23:00
@bobcatfish
Copy link
Copy Markdown
Contributor Author

image

YUUUUSSSSSS

Comment thread pkg/logging/config_test.go Outdated
}
}

func writeConfig(dir, key, value string) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copied @josephburnett 's unit tests for k8sflag here ;)

@bobcatfish
Copy link
Copy Markdown
Contributor Author

Okay so:

  1. Used @dprotaso 's suggestion to make a slightly more sophisticated function in logging.go, reducing the duplicate code
  2. I dropped the Debug line that logs the logging config b/c it messes up the interface BUT if you all feel strongly I will put it back

@mdemirhan @mattmoor @dprotaso PTAL

Comment thread pkg/logging/config.go

// DefaultLoggingConfigPath is the path where the zap logging
// config will be written in a default Knative deployment.
const DefaultLoggingConfigPath = "/etc/config-logging"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mattmoor let me know if you wanted me to do something more specific re 'not relying on /etc/config-logging'

Comment thread pkg/logging/config_test.go Outdated
// No good way to test if all the config is applied,
// but at the minimum, we can check and see if level is getting applied.
logger = NewLogger("{\"level\": \"error\", \"outputPaths\": [\"stdout\"],\"errorOutputPaths\": [\"stderr\"],\"encoding\": \"json\"}", "")
logger, err := NewLogger("{\"level\": \"error\", \"outputPaths\": [\"stdout\"],\"errorOutputPaths\": [\"stderr\"],\"encoding\": \"json\"}", "")
Copy link
Copy Markdown
Member

@dprotaso dprotaso Jun 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since you're changing a few NewLogger calls in these tests can you clean up all the escaping by using raw strings

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

niiiiiice

Comment thread pkg/logging/config_test.go Outdated

logger, err := NewDefaultConfigMapLogger(dir, "myfoo")
if err == nil {
t.Error("expecte error when creating logger from invalid config file")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😅

Comment thread pkg/logging/config_test.go Outdated
func TestNewDefaultConfigMapLogger(t *testing.T) {
dir, err := ioutil.TempDir("", "")
if err != nil {
panic(err)
Copy link
Copy Markdown
Member

@dprotaso dprotaso Jun 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using t.Fatal in these tests instead of panic will cause this to log to the test output buffer

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yeah, way better thanks!

Comment thread test/logging.go Outdated
}`
configJSON := fmt.Sprintf(configJSONTemplate, logLevel)
return logging.NewLogger(string(configJSON), logLevel)
logger, err := logging.NewLogger(string(configJSON), logLevel)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with the line change can you remove the unnecessary cast string(configJSON)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch, thanks!

Comment thread pkg/logging/config.go
// NewDefaultConfigMapLogger creates a logging object for the
// for the logLevelKey within configPath corresponding
// to the provided componentKey.
func NewDefaultConfigMapLogger(configPath string, componentKey string) (*zap.SugaredLogger, error) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given there is a default config path we can simplify the usability of this function a bit more by making configPath optional. Maybe it makes sense to name this function NewComponentLogger now?

ie.

func NewComponentLogger(componentKey string, configPath ...string) (*zap.SugaredLogger, error) {
  conf  := DefaultLoggingConfigPath
  if len(configPath) > 0 {
    conf = configPath[0]
  }

  ...
}

then the usage would simplified to

if logger, err := logging.NewComponentLogger("webhook"); err != nil {
	logger.Errorf("Error initializing logger: %s", err)
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for letting me know about this! i didn't know about variadic functions in Go!

however after looking into it a bit, I'm not sure I like the idea of using them for this optional params and here is an example of why. The TL;DidntRun is the fact that using a variadic args means callers can start passing you incorrect arguments have you have to either check and make sure they're not doing that explicitly or allow the weird extra arguments to silently not do anything, and neither option seems great

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup it's dirty - would you settle on having two New* functions

ie.

func NewComponentLogger(componentKey string) (*zap.SugaredLogger, error) {
  return NewComponentLoggerFromConfig(componentKey, DefaultLoggingConfigPath)
}

func NewComponentLoggerFromConfig(componentKey, configPath string) (*zap.SugaredLogger, error) {
   ...
}

@bobcatfish bobcatfish force-pushed the logging_in_log_lib branch from 441ef04 to 3dd0776 Compare June 28, 2018 18:28
Okay this is slightly more repeated code, but hear me out! When you log in
a library, it means the caller has no control over whether those
logs are emitted or not - case in point, the e2e tests are using this
library, and now they dump the json config and log level at the
beginning of every test, which we don't want and can't control.

This commit changes the `logging` lib such that it's the caller's
responsibility to decide whether to log or not.

This also changes the logic such that the logging configuration is no
longer logged at debug.
@bobcatfish bobcatfish force-pushed the logging_in_log_lib branch from 3dd0776 to 274973a Compare June 28, 2018 18:32
@bobcatfish
Copy link
Copy Markdown
Contributor Author

Ready for another round! PTAL @dprotaso @mattmoor @mdemirhan

@knative-metrics-robot
Copy link
Copy Markdown

The following is the coverage report on pkg/. Say /test pull-knative-serving-go-coverage to run the coverage report again

File Old Coverage New Coverage Delta
pkg/logging/config.go 77.8% 92.9% 15.1

*TestCoverage feature is being tested, do not rely on any info here yet

@bobcatfish
Copy link
Copy Markdown
Contributor Author

/test pull-knative-serving-integration-tests

@google-prow-robot
Copy link
Copy Markdown

@bobcatfish: The following test failed, say /retest to rerun them all:

Test name Commit Details Rerun command
pull-knative-serving-integration-tests 274973a link /test pull-knative-serving-integration-tests

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

@bobcatfish
Copy link
Copy Markdown
Contributor Author

Oh neat I think I actually broke something :D AND THE TESTS CAUGHT IIIIIT

@mattmoor
Copy link
Copy Markdown
Member

@bobcatfish FYI, my change to refactor the way we load things (to not be in the library!) landed. LMK when this is RFAL.

@mattmoor
Copy link
Copy Markdown
Member

/hold

Wait until after we cut first release.

@bobcatfish Are you going to come back to this PR?

@google-prow-robot google-prow-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jul 12, 2018
@mattmoor
Copy link
Copy Markdown
Member

I'm going to close this out. Feel free to reopen, if it's still relevant.

@mattmoor mattmoor closed this Jul 19, 2018
@bobcatfish
Copy link
Copy Markdown
Contributor Author

Yeah looks like I'm not going to be able to get back to this, esp. since the logging libs have changed significantly since I've last looked, thanks for closing it @mattmoor

I HAVE FAILED YOU @jonjohnsonjr :'(

I've created #1630 so hopefully someone can look into this in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants