feat(reporting): report duration on finish events
Proposed Commit Message
feat(reporting): report duration on finish events
- Ensure `ReportEventStack` computes elapsed time and passes it through `FinishReportingEvent` so all reporting handlers can emit durations.
- Capture the `duration` field in Hyper-V KVP metadata and adjust unit tests to assert the value is present.
- Note: any external callers constructing `FinishReportingEvent` will need to provide a duration argument.
Additional Context
ReportEventStacknow records a start timestamp and calculatesdurationon exit, feeding it intoreport_finish_event.FinishReportingEventexposes the duration inas_dictand string representations, allowing downstream consumers to quantify elapsed time without recomputing.HyperVKvpReportingHandlerincludes the duration field when serializing finish events, ensuring Azure KVP telemetry captures timing data.- Unit tests in
tests/unittests/reporting/test_reporting.pyandtests/unittests/reporting/test_reporting_hyperv.pywere updated to pass explicit durations and verify the new field, including the multi-slice Hyper-V KVP scenario. - Production test shows
durationin.kvp_pool_1entries forfinishevents:
CLOUD_INIT|1762464987|finish|modules-config/config-apt_configure|d0058170-3c82-412a-8437-e2f43a7c4258{"name":"modules-config/config-apt_configure","type":"finish","ts":"2025-11-06T21:36:51.542257+00:00","result":"SUCCESS","msg":"config-apt_configure ran successfully and took 0.089 seconds","duration":0.08879551900000138}
Merge type
- [x] Squash merge using "Proposed Commit Message"
The description text got mixed up with the other PR.
It looks like this is waiting for updates per the latest review (and CLA signature), so I'll hold off on reviewing it for now.
@holmanb @cjp256 I had added the duration to start events after an offline discussion, but have no preference on whether or not start events have one. Can adopt whatever approach you all think is best!
I think having duration in both start and finish events will allow us to not having to treat start/finish event differently, similar to how the result field exists for both start and finish events, even though you can't know the result of an operation at the start event
I think having duration in both start and finish events will allow us to not having to treat start/finish event differently, similar to how the
resultfield exists for bothstartandfinishevents, even though you can't know the result of an operation at the start event
Start event doesn't have a result. Example:
{
"description": "running config-install_hotplug with frequency once-per-instance",
"event_type": "start",
"name": "modules-final/config-install_hotplug",
"origin": "cloudinit",
"timestamp": 1765216665.916
},
{
"description": "config-install_hotplug ran successfully and took 0.001 seconds",
"event_type": "finish",
"name": "modules-final/config-install_hotplug",
"origin": "cloudinit",
"result": "SUCCESS",
"timestamp": 1765216665.917
},
Result is only defined for finished event:
https://github.com/canonical/cloud-init/blob/4537f0bb5c028b8005f451f82a60aacb74ddeea8/cloudinit/reporting/events.py#L86
I think having duration in both start and finish events will allow us to not having to treat start/finish event differently, similar to how the
resultfield exists for bothstartandfinishevents, even though you can't know the result of an operation at the start eventStart event doesn't have a result. Example:
{ "description": "running config-install_hotplug with frequency once-per-instance", "event_type": "start", "name": "modules-final/config-install_hotplug", "origin": "cloudinit", "timestamp": 1765216665.916 }, { "description": "config-install_hotplug ran successfully and took 0.001 seconds", "event_type": "finish", "name": "modules-final/config-install_hotplug", "origin": "cloudinit", "result": "SUCCESS", "timestamp": 1765216665.917 },Result is only defined for finished event:
https://github.com/canonical/cloud-init/blob/4537f0bb5c028b8005f451f82a60aacb74ddeea8/cloudinit/reporting/events.py#L86
My bad. Somehow I've been hallucinated into thinking that we had result for both start and finish. If this is the case, it makes sense to only have duration in the finish event. Thanks Chris for the fact-checking!