-
Notifications
You must be signed in to change notification settings - Fork 38
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
switch to structured logging #258
switch to structured logging #258
Conversation
Hi @pinikomarov. Thanks for your PR. I'm waiting for a openstack-k8s-operators member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. 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. |
@@ -87,7 +79,7 @@ type CinderSchedulerReconciler struct { | |||
|
|||
// Reconcile - | |||
func (r *CinderSchedulerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, _err error) { | |||
_ = log.FromContext(ctx) | |||
log := GetLog(ctx, "CinderBackup") |
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.
-1: All calls in this file should be using CinderScheduler
or CinderSch
whatever we prefer.
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.
right , correcting
controllers/cinder_controller.go
Outdated
@@ -223,6 +222,9 @@ func (r *CinderReconciler) SetupWithManager(mgr ctrl.Manager) error { | |||
// matches the name of an existing Cinder CR. In that case changes to that secret would trigger | |||
// reconciliation for a Cinder CR that does not need it. | |||
// | |||
|
|||
log := GetLog(ctx, "Cinder") |
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.
Is there any way to persist this, similar to how the previous code used r.log? My concern is that every function that wants to log something will need to repeat L226 in order to obtain its own 'log' object.
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'm experimenting with an alternative approach, and might submit my own PR just as a PoC.
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.
Hi Alan, we're trying the drop the use of the global logger in the struct,
We discussed it here :
It's to do with parallel reconcile use case and making room for differentiating each reconcile_id if that happens.
openstack-k8s-operators/keystone-operator#220 (comment)
Also the Gibbi believes that the pattern of of using the r.log from the global struct
to pass request specific info between different reconcile calls is not a good pattern.
Gibbi commented on the r.log usage here :
openstack-k8s-operators/nova-operator#496 (comment)
@gibizer fyi ^^
about placing the getLog.. func in the funcs module - cinder.GetLoggerWithContex , as in your patch ,I'm good with that either way
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.
Yepp. The Reconciler struct survives between Reconcile calls. Also it is shared between any parallel Reconcile calls. (At the moment I think we are not configured with parallel reconciliation but we can, and we might need that in the future to speed things up). In general we should not store any reconcile request specific data in the Reconciler struct due to this reason. The framework sets up the logger in the context with reconcile request specific data, like the uid of the resource to be reconciled.
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, this helps me understand why my alternate approach (sharing the Reconciler struct) isn't the right way to go. My hope was (and still is) there's a way for every function that wants to log something to not have to call GetLogger(). The main thing I'd like to avoid is the caller having to provide the controller name ("Cinder" vs "CinderAPI"). That would reduce the chance of a copy/paste error, where a function for controller X generates a log that looks like it came from controller Y (Gorka pointed out one such instance in this PR). Perhaps each controller could provide a local wrapper function, so the controller name is specified only once?
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 I see it we have to options here :
// Option 1:
// Per controller wrapper function that wraps the GetLog
func getLogWrapper(ctx context.Context) func(context.Context, string) logr.Logger{
return GetLog(ctx, "Heat")
}
//usage
func (...) Reconcile...
log := getLogWrapper(ctx)
// OR
// Option 2 ,at the head of each controller_.go we have a non exported local func with a statically named controller:
func getLog(ctx context.Context) logr.Logger {
return log.FromContext(ctx).WithName("Controllers").WithName("Heat")
}
//usage
func (...) Reconcile...
log := getLog(ctx)
// Either way I think about implementation, the simplest use case to seems to me is option 2.
WDYT ?
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.
Option 2 looks good to me
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 also prefer option 2.
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.
Another issue following that is that the getlog func signitures need to be unique across the controllers since they're all in the same "package controllers".
For that I think this can work :
each controller will get a unique get log sign.:
func cinderApiLog(ctx context.Context) logr.Logger ..
//usage :
func (..) Reconcile..ctrl.Result, _err error) {
log := cinderApiLog(ctx)
How's that ?
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.
fine by me
controllers/cinder_controller.go
Outdated
@@ -278,7 +280,8 @@ func (r *CinderReconciler) SetupWithManager(mgr ctrl.Manager) error { | |||
} | |||
|
|||
func (r *CinderReconciler) reconcileDelete(ctx context.Context, instance *cinderv1beta1.Cinder, helper *helper.Helper) (ctrl.Result, error) { | |||
r.Log.Info(fmt.Sprintf("Reconciling Service '%s' delete", instance.Name)) | |||
log := GetLog(ctx, "Cinder") |
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 is an example of what I referred to in my previous comment.
This represents a PoC that offers an alternative approach to pull request openstack-k8s-operators#258. Here is a sample of the outputs: 2023-09-21T08:09:42-07:00 INFO controllers.Cinder Reconciling Service 'cinder' {"controller": "cinder", "controllerGroup": "cinder.openstack.org", "controllerKind": "Cinder", "Cinder": {"na me":"cinder","namespace":"openstack"}, "namespace": "openstack", "name": "cinder", "reconcileID": "90ede6d8-c15a-44cb-b0b0-7e139e831f02"} 2023-09-21T08:09:42-07:00 INFO controllers.Cinder Reconciling Service 'cinder' init {"controller": "cinder", "controllerGroup": "cinder.openstack.org", "controllerKind": "Cinder", "Cinde r": {"name":"cinder","namespace":"openstack"}, "namespace": "openstack", "name": "cinder", "reconcileID": "90ede6d8-c15a-44cb-b0b0-7e139e831f02"} 2023-09-21T08:09:42-07:00 INFO controllers.Cinder Reconciled Service 'cinder' init successfully {"controller": "cinder", "controllerGroup": "cinder.openstack.org", "controllerKind": "Cinder" , "Cinder": {"name":"cinder","namespace":"openstack"}, "namespace": "openstack", "name": "cinder", "reconcileID": "90ede6d8-c15a-44cb-b0b0-7e139e831f02"} 2023-09-21T08:09:42-07:00 INFO controllers.Cinder Reconciling Service 'cinder' update {"controller": "cinder", "controllerGroup": "cinder.openstack.org", "controllerKind": "Cinder", "Cinde r": {"name":"cinder","namespace":"openstack"}, "namespace": "openstack", "name": "cinder", "reconcileID": "90ede6d8-c15a-44cb-b0b0-7e139e831f02"} 2023-09-21T08:09:42-07:00 INFO controllers.Cinder Reconciled Service 'cinder' update successfully {"controller": "cinder", "controllerGroup": "cinder.openstack.org", "controllerKind": "Cinder" , "Cinder": {"name":"cinder","namespace":"openstack"}, "namespace": "openstack", "name": "cinder", "reconcileID": "90ede6d8-c15a-44cb-b0b0-7e139e831f02"} 2023-09-21T08:09:42-07:00 INFO controllers.Cinder Reconciling Service 'cinder' upgrade {"controller": "cinder", "controllerGroup": "cinder.openstack.org", "controllerKind": "Cinder", "Cinde r": {"name":"cinder","namespace":"openstack"}, "namespace": "openstack", "name": "cinder", "reconcileID": "90ede6d8-c15a-44cb-b0b0-7e139e831f02"} 2023-09-21T08:09:42-07:00 INFO controllers.Cinder Reconciled Service 'cinder' upgrade successfully {"controller": "cinder", "controllerGroup": "cinder.openstack.org", "controllerKind": "Cinder", "Cinder": {"name":"cinder","namespace":"openstack"}, "namespace": "openstack", "name": "cinder", "reconcileID": "90ede6d8-c15a-44cb-b0b0-7e139e831f02"} 2023-09-21T08:09:42-07:00 INFO controllers.Cinder Reconciled Service 'cinder' successfully {"controller": "cinder", "controllerGroup": "cinder.openstack.org", "controllerKind": "Cinder" , "Cinder": {"name":"cinder","namespace":"openstack"}, "namespace": "openstack", "name": "cinder", "reconcileID": "90ede6d8-c15a-44cb-b0b0-7e139e831f02"} 2023-09-21T08:11:52-07:00 INFO controllers.CinderAPI Reconciling Service 'cinder-api' {"controller": "cinderapi", "controllerGroup": "cinder.openstack.org", "controllerKind": "CinderAPI", "CinderAPI": {"name":"cinder-api","namespace":"openstack"}, "namespace": "openstack", "name": "cinder-api", "reconcileID": "baa7a2f5-392a-4b7b-bf8a-1c4ca1b77183"} 2023-09-21T08:11:52-07:00 INFO controllers.CinderAPI Reconciling Service 'cinder-api' init {"controller": "cinderapi", "controllerGroup": "cinder.openstack.org", "controllerKind": "CinderAPI", "CinderAPI": {"name":"cinder-api","namespace":"openstack"}, "namespace": "openstack", "name": "cinder-api", "reconcileID": "baa7a2f5-392a-4b7b-bf8a-1c4ca1b77183"} 2023-09-21T08:11:52-07:00 INFO controllers.CinderAPI Service cinder-internal - updated {"controller": "cinderapi", "controllerGroup": "cinder.openstack.org", "controllerKind": "CinderAPI", "CinderAPI": {"name":"cinder-api","namespace":"openstack"}, "namespace": "openstack", "name": "cinder-api", "reconcileID": "baa7a2f5-392a-4b7b-bf8a-1c4ca1b77183"} 2023-09-21T08:11:52-07:00 INFO controllers.CinderAPI Service cinder-public - updated {"controller": "cinderapi", "controllerGroup": "cinder.openstack.org", "controllerKind": "CinderAPI", "CinderAPI": {"name":"cinder-api","namespace":"openstack"}, "namespace": "openstack", "name": "cinder-api", "reconcileID": "baa7a2f5-392a-4b7b-bf8a-1c4ca1b77183"} 2023-09-21T08:11:52-07:00 INFO controllers.CinderAPI Route cinder-public - updated {"controller": "cinderapi", "controllerGroup": "cinder.openstack.org", "controllerKind": "CinderAPI", "CinderAPI": {"name":"cinder-api","namespace":"openstack"}, "namespace": "openstack", "name": "cinder-api", "reconcileID": "baa7a2f5-392a-4b7b-bf8a-1c4ca1b77183"} 2023-09-21T08:11:52-07:00 INFO controllers.CinderAPI Reconciled Service 'cinder-api' init successfully {"controller": "cinderapi", "controllerGroup": "cinder.openstack.org", "controllerKind": "CinderAPI", "CinderAPI": {"name":"cinder-api","namespace":"openstack"}, "namespace": "openstack", "name": "cinder-api", "reconcileID": "baa7a2f5-392a-4b7b-bf8a-1c4ca1b77183"}
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 all the hard work to improve our logging :-)
controllers/cinder_controller.go
Outdated
func (r *CinderReconciler) GetLogger() logr.Logger { | ||
return r.Log | ||
// getLog returns a logger object with a logging prefix of "conrollers.name" and aditional controller context fields | ||
func cinderLog(ctx context.Context) logr.Logger { |
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.
-1: Please make this a struct method like it was before, all you need to do is add the new method argument.
func (r *CinderReconciler) GetLogger(ctx context.Context) logr.Logger {
That way the name remains the same regardless of the controller we are in and we'll always do log := r.GetLogger(ctx)
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 think the code is ready to be merged, could you squash all the commits into 1 please?
And rebase it, because it's in conflict.
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 PR is moving in the right direction, but I want us to consider another update.
I also agree with Gorka's note about rebasing and squashing the commits.
controllers/cinder_controller.go
Outdated
@@ -138,7 +137,7 @@ func (r *CinderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res | |||
r.Client, | |||
r.Kclient, | |||
r.Scheme, | |||
r.Log, | |||
log, |
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 really like the idea of adding the logger function to the helper !!!
But can we call it Log (capital 'L')? See how it will be referenced in a comment below.
controllers/cinder_controller.go
Outdated
@@ -278,7 +280,8 @@ func (r *CinderReconciler) SetupWithManager(mgr ctrl.Manager) error { | |||
} | |||
|
|||
func (r *CinderReconciler) reconcileDelete(ctx context.Context, instance *cinderv1beta1.Cinder, helper *helper.Helper) (ctrl.Result, error) { | |||
r.Log.Info(fmt.Sprintf("Reconciling Service '%s' delete", instance.Name)) | |||
log := r.getLog(ctx) |
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.
Why not use the logger that's available in the helper?
helper.Log.Info(...)
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.
For me the Helper is a dumping ground of unrelated utility functions. See https://wiki.c2.com/?AbuseOfUtilityClasses So my ultimate goal is not to add things to it but actually dissolve it in the long run.
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 had a stab at having a separate logger package openstack-k8s-operators/lib-common#125 but it turned out that we already get a proper logger via the ctx anyway so that package would be fairly empty.
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.
So where does that leave us? It seems reasonable for every controller to have its own logger function, and the question is how to provide easy access to that function. I agree the Helper shouldn't be a dumping ground, but if we avoid using it then we'll need some other way to forward.
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.
the ctx
is already passed around and the ctx
already contains a logger to use. So the r.getLog(ctx)
is good for me.
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.e for me the difference between helper.Log.Info(...)
an r.getLog(ctx).Info()
is that ctx is the framework's way to pass a logger to us and we already have the context in most places, so pulling the logger out of context and adding it to the helper seems like an unnecessary complication to me.
controllers/cinder_controller.go
Outdated
@@ -309,7 +312,8 @@ func (r *CinderReconciler) reconcileInit( | |||
serviceLabels map[string]string, | |||
serviceAnnotations map[string]string, | |||
) (ctrl.Result, error) { | |||
r.Log.Info(fmt.Sprintf("Reconciling Service '%s' init", instance.Name)) | |||
log := r.getLog(ctx) | |||
log.Info(fmt.Sprintf("Reconciling Service '%s' init", instance.Name)) |
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.
Same as before. Just replace "r.Log()" with "helper.Log()"
9368890
to
fa51328
Compare
fa51328
to
0656194
Compare
0656194
to
be6d470
Compare
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.
+1 from me, though I'd like to see feedback from @Akrog .
Also see my comment on how we might take the opportunity to remove the Log element from helpers.
@@ -116,7 +115,7 @@ type CinderReconciler struct { | |||
|
|||
// Reconcile - | |||
func (r *CinderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, _err error) { | |||
_ = log.FromContext(ctx) | |||
Log := r.GetLogger(ctx) |
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 still wish it was possible to pass the logger function down the call stack in order to minimize the number of places that have to call this function. But maybe I just need to get used to a new (to me) convention.
@@ -137,7 +136,7 @@ func (r *CinderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res | |||
r.Client, | |||
r.Kclient, | |||
r.Scheme, | |||
r.Log, | |||
Log, |
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.
@gibizer I recall you saying you'd like to reduce (eliminate?) our use of helpers. With this PR, the Log element in the helper is no longer used by the controller, but we have to supply one in order create the helper. It looks like we have an opportunity to remove the Log from the helper (since nobody will use it), but I don't know how to coordinate doing that across all the repos that use the current helper. Any thoughts on that?
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 agree, we could have had a PR to remove the parameter in lib-common, and then bump its pinning here in this same PR so we could remove the passing of the parameter in one go.
With the current approach we need to:
- Merge this PR
- Remove the code from lib-common that requires the logger argument
- Update the pinning in all the operators at the same time we remove the passing of the argument.
Our current approach seems more painful, but for the shake of getting things done and keep moving we can merge it.
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
@@ -137,7 +136,7 @@ func (r *CinderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res | |||
r.Client, | |||
r.Kclient, | |||
r.Scheme, | |||
r.Log, | |||
Log, |
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 agree, we could have had a PR to remove the parameter in lib-common, and then bump its pinning here in this same PR so we could remove the passing of the parameter in one go.
With the current approach we need to:
- Merge this PR
- Remove the code from lib-common that requires the logger argument
- Update the pinning in all the operators at the same time we remove the passing of the argument.
Our current approach seems more painful, but for the shake of getting things done and keep moving we can merge it.
recheck |
b2b7e24
to
c845ee1
Compare
c98a06a
to
5c00980
Compare
643322b
to
5c00980
Compare
6b453d1
to
7be72e3
Compare
7be72e3
to
52d9e8d
Compare
52d9e8d
to
6ebe581
Compare
6ebe581
to
106d164
Compare
106d164
to
9de278d
Compare
9de278d
to
3a466a1
Compare
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.
+1
/retest |
@pinikomarov: The following test failed, say
Full PR test history. Your PR dashboard. 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. |
fix client.list params update test logging
3a466a1
to
375ec51
Compare
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: Akrog, ASBishop, pinikomarov 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 |
fef9f1c
into
openstack-k8s-operators:main
This automatically adds additional fields like reconcile_id etc.. from the controller context.
before :
2023-05-18T01:53:14+03:00 INFO controllers.KeystoneAPI Reconciled Service init successfully
after:
2023-10-04T16:06:31+03:00 INFO Controllers.CinderAPI Reconciled Service 'cinder-api' successfully {"controller": "cinderapi", "controllerGroup": "cinder.openstack.org", "controllerKind": "CinderAPI", "CinderAPI": {"name":"cinder-api","namespace":"openstack"}, "namespace": "openstack", "name": "cinder-api", "reconcileID": "09fed477-8ad5-4186-8b20-790f409de78a"}
*by using per reconcile function respective logger objects, the intention is to lay the ground for parallel reconciliation in future and avoid race conditions as ctx objects are reconcile run specific.