Skip to content
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

Fix broken json logging #6779

Merged
merged 1 commit into from Feb 21, 2024
Merged

Conversation

inteon
Copy link
Member

@inteon inteon commented Feb 21, 2024

Fixes #6768

In #6587 (https://github.com/cert-manager/cert-manager/pull/6587/files#diff-8f2f7b96261d29c4991c0025fde03c2edb0411a9aa7afaa834b5cf19837b5b2eL41), I updated the global Log definition in log.go.
I based the updated code on the deprecation message of the klogr.NewWithOptions() command that we were using.
It seems like the proposed replacement textlogger.NewLogger(textlogger.NewConfig()) does not get updated when we parse & set the logging flags.

This PR fixes this bug by using klog.Background() instead.

Before:

$ k -n cert-manager logs cert-manager-78dd8d6947-br2h8 
{"ts":1708504242845.5793,"caller":"clientcmd/client_config.go:618","msg":"Neither --kubeconfig nor --master was specified.  Using the inClusterConfig.  This might not work.","v":0}
I0221 08:30:42.851118       1 options.go:248] "enabling all experimental certificatesigningrequest controllers" logger="cert-manager"
I0221 08:30:42.851135       1 options.go:253] "enabling the sig-network Gateway API certificate-shim and HTTP-01 solver" logger="cert-manager"
I0221 08:30:42.851148       1 controller.go:89] "enabled controllers: [certificaterequests-approver certificaterequests-issuer-acme certificaterequests-issuer-ca certificaterequests-issuer-selfsigned certificaterequests-issuer-vault certificaterequests-issuer-venafi certificates-issuing certificates-key-manager certificates-metrics certificates-readiness certificates-request-manager certificates-revision-manager certificates-trigger certificatesigningrequests-issuer-acme certificatesigningrequests-issuer-ca certificatesigningrequests-issuer-selfsigned certificatesigningrequests-issuer-vault certificatesigningrequests-issuer-venafi challenges clusterissuers gateway-shim ingress-shim issuers orders]" logger="cert-manager.controller"
{"ts":1708504242853.3452,"caller":"leaderelection/leaderelection.go:250","msg":"attempting to acquire leader lease kube-system/cert-manager-controller...","v":0}

After:

$ k -n cert-manager logs cert-manager-78dd8d6947-64kcb 
{"ts":1708504356076.2844,"caller":"app/controller.go:288","msg":"configured acme dns01 nameservers","v":2,"logger":"cert-manager.controller.build-context","nameservers":["10.0.0.16:53"]}
{"ts":1708504356076.3547,"caller":"clientcmd/client_config.go:618","msg":"Neither --kubeconfig nor --master was specified.  Using the inClusterConfig.  This might not work.","v":0}
{"ts":1708504356085.3008,"caller":"options/options.go:248","msg":"enabling all experimental certificatesigningrequest controllers","v":0,"logger":"cert-manager"}
{"ts":1708504356085.322,"caller":"options/options.go:253","msg":"enabling the sig-network Gateway API certificate-shim and HTTP-01 solver","v":0,"logger":"cert-manager"}
{"ts":1708504356085.3352,"caller":"app/controller.go:89","msg":"enabled controllers: [certificaterequests-approver certificaterequests-issuer-acme certificaterequests-issuer-ca certificaterequests-issuer-selfsigned certificaterequests-issuer-vault certificaterequests-issuer-venafi certificates-issuing certificates-key-manager certificates-metrics certificates-readiness certificates-request-manager certificates-revision-manager certificates-trigger certificatesigningrequests-issuer-acme certificatesigningrequests-issuer-ca certificatesigningrequests-issuer-selfsigned certificatesigningrequests-issuer-vault certificatesigningrequests-issuer-venafi challenges clusterissuers gateway-shim ingress-shim issuers orders]","v":0,"logger":"cert-manager.controller"}
{"ts":1708504356085.3403,"caller":"app/controller.go:435","msg":"serving insecurely as tls certificate data not provided","v":1,"logger":"cert-manager.controller"}
{"ts":1708504356085.345,"caller":"app/controller.go:102","msg":"listening for insecure connections","v":2,"logger":"cert-manager.controller","address":"0.0.0.0:9402"}
{"ts":1708504356085.5166,"caller":"app/controller.go:182","msg":"starting leader election","v":2,"logger":"cert-manager.controller"}
{"ts":1708504356085.534,"caller":"app/controller.go:129","msg":"starting metrics server","v":2,"logger":"cert-manager.controller","address":"[::]:9402"}
{"ts":1708504356085.5508,"caller":"app/controller.go:175","msg":"starting healthz server","v":2,"logger":"cert-manager.controller","address":"[::]:9403"}
{"ts":1708504356087.196,"caller":"leaderelection/leaderelection.go:250","msg":"attempting to acquire leader lease kube-system/cert-manager-controller...","v":0}

Kind

/kind bug

Release Note

BUGFIX: Fixes issue with JSON-logging, where only a subset of the log messages were output as JSON.

@jetstack-bot jetstack-bot added release-note-none Denotes a PR that doesn't merit a release note. dco-signoff: yes Indicates that all commits in the pull request have the valid DCO sign-off message. needs-kind Indicates a PR lacks a `kind/foo` label and requires one. size/XS Denotes a PR that changes 0-9 lines, ignoring generated files. labels Feb 21, 2024
@inteon inteon requested a review from wallrj February 21, 2024 09:07
@jetstack-bot jetstack-bot added release-note Denotes a PR that will be considered when it comes time to generate release notes. and removed release-note-none Denotes a PR that doesn't merit a release note. labels Feb 21, 2024
@inteon
Copy link
Member Author

inteon commented Feb 21, 2024

/cherrypick release-1.14

@jetstack-bot
Copy link
Collaborator

@inteon: once the present PR merges, I will cherry-pick it on top of release-1.14 in a new PR and assign it to you.

In response to this:

/cherrypick release-1.14

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.

Copy link
Member

@wallrj wallrj left a comment

Choose a reason for hiding this comment

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

Thanks @inteon

I tested it locally and observed that controller, webhook, cainjector, and startupapicheck now all log using text format by default and log in json format when you supply --logging-format=json.

acmesolver does not have a --logging-format option and logs in text format by default.

$ go run ./cmd/acmesolver/
I0221 09:59:01.936360  237080 solver.go:51] "starting listener" logger="cert-manager.acmesolver" expected_domain="" expected_token="" expected_key="" listen_port=8089
^CError: http: Server closed
Usage:
  acmesolver [flags]

Flags:
      --domain string     the domain name to verify
  -h, --help              help for acmesolver
      --key string        the challenge key to respond with
      --listen-port int   the port number to listen on for connections (default 8089)
      --token string      the challenge token to verify against

E0221 09:59:08.412760  237080 main.go:39] "error executing command" err="http: Server closed" logger="cert-manager"
exit status 1

startupapicheck check api --logging-format=json logs the --help output and a non-json message "exit status 1" to stderr when it exits if it fails.

$ go run ./cmd/startupapicheck check api --logging-format=json >/dev/null
...
  -v, --v Level[=2]                    number for the log level verbosity
      --vmodule pattern=N,...          comma-separated list of pattern=N settings for file-filtered logging (only works for text log format)

{"ts":1708509667519.7598,"caller":"startupapicheck/main.go:81","msg":"error executing command","logger":"cert-manager","err":"the cert-manager CRDs are not yet installed on the Kubernetes API server"}
exit status 1

All the components seem to print the --help contents to stderr when they fail. Here's another example.

$ go run ./cmd/cainjector/ --logging-format=json >/dev/null
{"ts":1708510096166.3782,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510097162.4548,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510098167.0452,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510099162.8765,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510100162.8022,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510101163.4583,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510102162.845,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510103163.0078,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510104162.4485,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510105164.5286,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510106163.504,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510107164.492,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510108164.838,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510109164.4238,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510110162.733,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510111164.6616,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510112163.48,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510113165.1387,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510114163.4695,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510115164.6423,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510116165.3406,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510117161.9958,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510118164.8777,"caller":"app/controller.go:149","msg":"cainjector has been configured to watch certificates, but certificates.cert-manager.io CRD not found, retrying with a backoff...","v":0,"logger":"cert-manager.cainjector"}
{"ts":1708510120244.8757,"caller":"app/controller.go:152","msg":"error checking if certificates.cert-manager.io CRD is installed","logger":"cert-manager.cainjector","err":"Get \"https://127.0.0.1:46421/apis/apiextensions.k8s.io/v1/customresourcedefinitions/certificates.cert-manager.io\": dial tcp 127.0.0.1:46421: connect: connection refused - error from a previous attempt: EOF"}
{"ts":1708510120245.0347,"caller":"app/controller.go:159","msg":"error retrieving certificate.cert-manager.io CRDs","logger":"cert-manager.cainjector","err":"Get \"https://127.0.0.1:46421/apis/apiextensions.k8s.io/v1/customresourcedefinitions/certificates.cert-manager.io\": dial tcp 127.0.0.1:46421: connect: connection refused - error from a previous attempt: EOF"}
Error: Get "https://127.0.0.1:46421/apis/apiextensions.k8s.io/v1/customresourcedefinitions/certificates.cert-manager.io": dial tcp 127.0.0.1:46421: connect: connection refused - error from a previous attempt: EOF
Usage:
  cainjector [flags]

Flags:
      --config string                                       Path to a file containing a CAInjectorConfiguration object used to configure the controller
      --enable-apiservices-injectable                       Inject CA data to annotated APIServices. This functionality is not required if cainjector is only used as cert-manager's internal component and setting it to false might reduce memory consumption (default true)
      --enable-certificates-data-source                     Enable configuring cert-manager.io Certificate resources as potential sources for CA data. Requires cert-manager.io Certificate CRD to be installed. This data source can be disabled to reduce memory consumption if you only use cainjector as part of cert-manager's installation (default true)
      --enable-customresourcedefinitions-injectable         Inject CA data to annotated CustomResourceDefinitions. This functionality is not required if cainjecor is only used as cert-manager's internal component and setting it to false might slightly reduce memory consumption (default true)
      --enable-mutatingwebhookconfigurations-injectable     Inject CA data to annotated MutatingWebhookConfigurations. This functionality is required for cainjector to work correctly as cert-manager's internal component (default true)
      --enable-profiling                                    Enable profiling for controller.
      --enable-validatingwebhookconfigurations-injectable   Inject CA data to annotated ValidatingWebhookConfigurations. This functionality is required for cainjector to correctly function as cert-manager's internal component (default true)
      --feature-gates mapStringBool                         A set of key=value pairs that describe feature gates for alpha/experimental features. Options are:
                                                            AllAlpha=true|false (ALPHA - default=false)
                                                            AllBeta=true|false (BETA - default=false)
                                                            ServerSideApply=true|false (ALPHA - default=false)
  -h, --help                                                help for cainjector
      --kubeconfig string                                   Paths to a kubeconfig. Only required if out-of-cluster.
      --leader-elect                                        If true, cainjector will perform leader election between instances to ensure no more than one instance of cainjector operates at a time
      --leader-election-lease-duration duration             The duration that non-leader candidates will wait after observing a leadership renewal until attempting to acquire leadership of a led but unrenewed leader slot. This is effectively the maximum duration that a leader can be stopped before it is replaced by another candidate. This is only applicable if leader election is enabled.
      --leader-election-namespace string                    Namespace used to perform leader election. Only used if leader election is enabled
      --leader-election-renew-deadline duration             The interval between attempts by the acting master to renew a leadership slot before it stops leading. This must be less than or equal to the lease duration. This is only applicable if leader election is enabled.
      --leader-election-retry-period duration               The duration the clients should wait between attempting acquisition and renewal of a leadership. This is only applicable if leader election is enabled.
      --log-flush-frequency duration                        Maximum number of seconds between log flushes (default 5s)
      --logging-format string                               Sets the log format. Permitted formats: "json" (gated by LoggingBetaOptions), "text". (default "text")
      --namespace string                                    If set, this limits the scope of cainjector to a single namespace. If set, cainjector will not update resources with certificates outside of the configured namespace.
      --profiler-address string                             The host and port that Go profiler should listen on, i.e localhost:6060. Ensure that profiler is not exposed on a public address. Profiler will be served at /debug/pprof. (default "localhost:6060")
  -v, --v Level                                             number for the log level verbosity
      --vmodule pattern=N,...                               comma-separated list of pattern=N settings for file-filtered logging (only works for text log format)

{"ts":1708510120246.381,"caller":"cainjector/main.go:40","msg":"error executing command","logger":"cert-manager","err":"Get \"https://127.0.0.1:46421/apis/apiextensions.k8s.io/v1/customresourcedefinitions/certificates.cert-manager.io\": dial tcp 127.0.0.1:46421: connect: connection refused - error from a previous attempt: EOF"}
exit status 1

These all seem like issues we should address if we want to properly fix the problem @petermajn reported:

Logging-format json sometimes writes plaintext messages

So I'd be inclined to remove the "Fixes: " line from the PR description.

But I like that this PR is small and easy to review and gets cert-manager back to where it was in 1.13 and can be easily cherrypicked into previous release branches if necessary.

We should create followup PRs to ensure that all the components only print json to stderr if they are configured that way.
And we should create a followup PR to test our json logging, maybe by setting --logging-format=json in all our E2E components and checking for invalid json that has been logged during the tests.

/approve
/lgtm
/hold in case you agree that TODO is the correct function to use and in case you agree that it needs a comment explaining that it is a temporary solution while we update all the code to get loggers from arguments or from context.

pkg/logs/logs.go Outdated

"github.com/cert-manager/cert-manager/pkg/api"
)

var (
Log = textlogger.NewLogger(textlogger.NewConfig()).WithName("cert-manager")
Log = klog.Background().WithName("cert-manager")
Copy link
Member

Choose a reason for hiding this comment

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

The documentation for this function suggests that it should be marked as a TODO item (and called as klog.TODO()) to remind us to fix this in the near future:
https://github.com/kubernetes/klog/blob/007e661a007dacdf017ad9c1b53e9f96d32d4b7d/contextual.go#L166-L185

Background retrieves the fallback logger. It should not be called before that logger was initialized by the program and not by code that should better receive a logger via its parameters. TODO can be used as a temporary solution for such code.

TODO can be used as a last resort by code that has no means of receiving a logger from its caller. FromContext or an explicit logger parameter should be used instead.

So perhaps using TODO would make it clearer that this is something we need to fix.

@jetstack-bot jetstack-bot added do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. lgtm Indicates that a PR is ready to be merged. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Feb 21, 2024
Signed-off-by: Tim Ramlot <42113979+inteon@users.noreply.github.com>
@jetstack-bot jetstack-bot removed the lgtm Indicates that a PR is ready to be merged. label Feb 21, 2024
Copy link
Member

@wallrj wallrj left a comment

Choose a reason for hiding this comment

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

Thanks.

/lgtm
/unhold

@jetstack-bot jetstack-bot added lgtm Indicates that a PR is ready to be merged. and removed do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. labels Feb 21, 2024
@jetstack-bot
Copy link
Collaborator

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: wallrj

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

The pull request process is described here

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

@wallrj
Copy link
Member

wallrj commented Feb 21, 2024

/kind bug

@jetstack-bot jetstack-bot added kind/bug Categorizes issue or PR as related to a bug. and removed needs-kind Indicates a PR lacks a `kind/foo` label and requires one. labels Feb 21, 2024
@jetstack-bot jetstack-bot merged commit 3204b21 into cert-manager:master Feb 21, 2024
7 checks passed
@jetstack-bot
Copy link
Collaborator

@inteon: new pull request created: #6781

In response to this:

/cherrypick release-1.14

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.

@maelvls
Copy link
Member

maelvls commented Feb 22, 2024

Does this bug affects any released version of cert-manager? Yes, 1.14 is affected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. dco-signoff: yes Indicates that all commits in the pull request have the valid DCO sign-off message. kind/bug Categorizes issue or PR as related to a bug. lgtm Indicates that a PR is ready to be merged. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XS Denotes a PR that changes 0-9 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Logging-format json sometimes writes plaintext messages
4 participants