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

Implemented reconcile metrics #384

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

KirrTap
Copy link

@KirrTap KirrTap commented Aug 26, 2024

Added metrics to the reconcilers

@KirrTap KirrTap requested review from lukasfrank and lukas016 August 26, 2024 08:54
@KirrTap KirrTap self-assigned this Aug 26, 2024
@lukas016 lukas016 assigned lukas016 and unassigned KirrTap Sep 23, 2024
@lukas016 lukas016 force-pushed the osc/sd-queue-metrics-poc branch 3 times, most recently from dd8fd53 to f0a1ec9 Compare September 24, 2024 08:15
@lukas016 lukas016 force-pushed the osc/sd-queue-metrics-poc branch from f0a1ec9 to 96c98dc Compare September 24, 2024 08:22
@lukas016 lukas016 marked this pull request as ready for review September 24, 2024 08:23
@lukas016 lukas016 requested a review from a team as a code owner September 24, 2024 08:23
Comment on lines 238 to 241
const name = "volume-size"
log = log.WithName(name)
opsDuration := metrics.OperationDuration.WithLabelValues(name)
opsErrors := metrics.OperationErrors.WithLabelValues(name)
Copy link
Member

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?

Copy link
Contributor

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)
  ...

Copy link
Member

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.

Copy link
Contributor

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.

Choose a reason for hiding this comment

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

Dissecting the requests here.

  1. 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

  2. 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))
Copy link
Member

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

Comment on lines 125 to 127
metricsReconcileDuration: metrics.ControllerRuntimeReconcileDuration.WithLabelValues(MachineReconcilerName),
metricsControllerRuntimeActiveWorker: metrics.ControllerRuntimeActiveWorker.WithLabelValues(MachineReconcilerName),
metricsControllerRuntimeReconcileErrors: metrics.ControllerRuntimeReconcileErrors.WithLabelValues(MachineReconcilerName),
Copy link
Member

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

Copy link
Contributor

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.

Copy link
Member

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.

Copy link
Contributor

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())
		})
	})
})

Copy link
Member

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.

Copy link
Contributor

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.

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.

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{
Copy link
Member

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?

Copy link
Contributor

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.

Copy link
Contributor

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)

@lukasfrank lukasfrank changed the title Metrics for reconciles machine time Implemented reconcile metrics Sep 26, 2024
@lukas016 lukas016 force-pushed the osc/sd-queue-metrics-poc branch from af10519 to 6de1d96 Compare October 18, 2024 12:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Todo
Development

Successfully merging this pull request may close these issues.

4 participants