-
Notifications
You must be signed in to change notification settings - Fork 5
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
Implemented reconcile metrics #384
base: main
Are you sure you want to change the base?
Implemented reconcile metrics #384
Conversation
dd8fd53
to
f0a1ec9
Compare
f0a1ec9
to
96c98dc
Compare
const name = "volume-size" | ||
log = log.WithName(name) | ||
opsDuration := metrics.OperationDuration.WithLabelValues(name) | ||
opsErrors := metrics.OperationErrors.WithLabelValues(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.
Can we keep passing the prepared logger and maybe define a global name like you did for MachineReconcilerName
?
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.
about passing argument i am not completely sure. I personally suggest remove passing over argument and directly initialize in function log from r.log. because passing of arguments doesn't add any benefits because start.. functions are methods of MachineReconciler and they have direct access to main logger. Now we just "spilitting" configuration of operation into 2 functions. I prefer keep it together.
My suggestion:
func (r *MachineReconciler) startCheckAndEnqueueVolumeResize(ctx context.Context) {
log := r.log.WithName(MachineReconcilerVolumeSize)
...
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.
WithName
adds context and appends the name to the existing 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.
I really don't understand why are you giving me here function description and you don't react usefully to my comment.
But okay it appends name separate with .
, if you want to see whole description.
But it is useless, if we discuss how passing child logger into function.
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.
Dissecting the requests here.
-
Request to introduce global consts for the individual logger decorators: I agree with @lukasfrank here, being consistent here is introducing a const for each decorator name similar to https://github.com/ironcore-dev/libvirt-provider/pull/384/files#diff-a2d4663c7af1f98625f6b53f602e53ce910de934bd827f232e31db91bf9bb5acR49
-
Injecting vs. Self-decorating: This is a bit of a matter of taste in this particular spot. You can argue for both sides, keeping the injection by method argument enables the method to just use whatever logger is passed in and go with it. Also, configuration is kept outside of the method itself and is done by the calling instance. The self-decorating approach @lukas016 suggests is also valid as it encapsulates the responsibilities for behavior in the
start...
methods. Ultimately, the suggestion by @lukas016 is a good compromise:
func (r *MachineReconciler) startCheckAndEnqueueVolumeResize(ctx context.Context) {
log := r.log.WithName(MachineReconcilerVolumeSize)
...
When testing, you pass in your mock logging provider to the containing reconciler struct and the start...
methods consume this, with also self-contained decorators.
} | ||
|
||
func (r *MachineReconciler) Start(ctx context.Context) error { | ||
log := r.log | ||
|
||
//todo make configurable | ||
workerSize := 15 | ||
metrics.ControllerRuntimeMaxConccurrentReconciles.WithLabelValues("machine-reconciler").Set(float64(workerSize)) |
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.
pls use the const here
metricsReconcileDuration: metrics.ControllerRuntimeReconcileDuration.WithLabelValues(MachineReconcilerName), | ||
metricsControllerRuntimeActiveWorker: metrics.ControllerRuntimeActiveWorker.WithLabelValues(MachineReconcilerName), | ||
metricsControllerRuntimeReconcileErrors: metrics.ControllerRuntimeReconcileErrors.WithLabelValues(MachineReconcilerName), |
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 are the metrics not passed as options? It makes it hard to pass a mock metric provider in tests
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 do you want to mock metrics? these metrics has to represent internal stuff of controller (errors, workers, ...) and they don't have any special logic so you can create them in unit tests and it will work.
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.
You can pass your own simple implementation in order to check the functionality.
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 checked that and i don't think we need mocking interface.
You can very nice test metrics directly with testutil package from prometheus without web server:
var _ = Describe("Controller runtime metrics", func() {
Context("metric ControllerRuntimeReconcileErrors", func() {
It("should increment metric", func() {
m := metrics.ControllerRuntimeReconcileErrors.WithLabelValues(controllers.MachineReconcilerName)
m.Inc()
m.Inc()
expectedMetric := `
# HELP controller_runtime_reconcile_errors_total Total number of reconciliation errors per controller
# TYPE controller_runtime_reconcile_errors_total counter
controller_runtime_reconcile_errors_total{controller="machine-reconciler"} 2
`
reader := strings.NewReader(expectedMetric)
Expect(testutil.GatherAndCompare(prometheus.DefaultGatherer, reader, "controller_runtime_reconcile_errors_total")).ToNot(HaveOccurred())
})
})
})
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 code above describes a test case which checks if you can increment a metrics counter, which is covered already by the lib.
I'm talking about a test where we create a resource, and check if metric x
, or y
is as expected.
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.
you have it described 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.
What @lukasfrank means here is to add fields in the opts struct https://github.com/ironcore-dev/libvirt-provider/blob/main/internal/controllers/machine_controller.go#L64 which are created before the reconciler object is instantiated and injected from the outside. I agree that this enables better testing because you are not relying on prometheus library when testing your own reconciler here, as you will provide a mock provider for the metrics.
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.
applied in faaa29b
@@ -98,24 +101,30 @@ func NewMachineReconciler( | |||
} | |||
|
|||
return &MachineReconciler{ |
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 we add at least a simple 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.
without support of mocking we can just create integration 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.
we can implement both see my comment: #384 (comment)
af10519
to
6de1d96
Compare
Added metrics to the reconcilers