[ADD] monitoring_prometheus_queue_job - #529
gurneyalex wants to merge 1 commit into
Conversation
062eebf to
33bfbfe
Compare
twalter-c2c
left a comment
There was a problem hiding this comment.
Looks good, AFAICT. Pre-commit needs to be satisfied. I dropped a few tiny comments, but they are not relevant to the code logic. Pre-approving.
| "version": "14.0.1.0.0", | ||
| "author": "Camptocamp,Odoo Community Association (OCA)", | ||
| "license": "AGPL-3", | ||
| "category": "category", |
There was a problem hiding this comment.
Do we want a more accurate category name? 😉
| @@ -0,0 +1,42 @@ | |||
| # Copyright 2016-2021 Camptocamp SA | |||
There was a problem hiding this comment.
| # Copyright 2016-2021 Camptocamp SA | |
| # Copyright 2026 Camptocamp SA |
| """Collect application metrics to be exposed on the /metrics endpoint. | ||
|
|
||
| Metrics are gathered by a cron and stored as JSON in an | ||
| ``ir.config_parameter``, because crons and HTTP workers run in |
There was a problem hiding this comment.
It is interesting, but there's no better choice to store metrics, than ir.config_parameter?
I was just curious if it is a pattern used elsewhere.
There was a problem hiding this comment.
We can materialize a model for this. The main thing is that the value is gathered in one worker (the cron) and served over http, so we need to store it somewhere, we cannot keep it in memory (which is what is done for the http metrics in the module (which are useless btw, but this is a different issue). I also wanted to avoid having the /metrics endpoint make potentially complex SQL queries, to keep it fast.
I chose ir.config_parameter because it is guaranteed to be present and kind of "made sense" . What I did not check is if there is a cache invalidation involved when we update it (we certainly don't want that) -> will double check.
There was a problem hiding this comment.
There was a problem hiding this comment.
Possible alternatives could be:
ir.loggingwhich is not used much- an attachment on
ir.cronrecord with id"monitoring_prometheus.cron_prometheus_gather_metrics"
It could be a singleton record with an "external ID" to retrieve it with env.ref("monitoring_prometheus.metrics") for example and you're done.
There was a problem hiding this comment.
I added a prometheus.metric model
SilvioC2C
left a comment
There was a problem hiding this comment.
Overall LGTM; wondering if there's a better alternative to storing log values in a sys param (especially cause they can be edited manually from the UI), but definitely not a blocker
There was a problem hiding this comment.
TL;DR:
- I don't see the benefit of the cron over doing the request on-the-fly when
/metricsis called. We can simply configure prometheus to pull only every 15min - If there is a reason for it, I would prefer to use a prometheus collector and push to it from the cron instead.
| return [] | ||
|
|
||
| @api.model | ||
| def _cron_gather_metrics(self): |
There was a problem hiding this comment.
Why the cron
I don't really see the benefit of using a cron here.
If prometheus pull faster than the cron, it will store the same value over and over.
If there is a reason for that, maybe we should use a collector in push mode.
For example Prometheus Pushgateway or OpenTelemetry collector:
- The cron push data directly to it
- Prometheus collect from the collector
Prometheus itself accepts push, but it's usually preferable to keep it in pull mode.
This would at least offload Odoo and also avoid the ir.config_parameter trick.
The /metrics route only makes sense if we serve fresh data IMO.
Naming
It's a bit confusing here:
We also have _gather_queue_job_metrics, similar name, that actually extend _gather_metrics
This method should maybe be called _cron_persist_metrics
There was a problem hiding this comment.
Having a cron and storing the values means that they are collected once and for all, because these values are shared by all the workers which are part of the instance. I was concerned about hitting the database too hard with 15 pods being queried at the same time by prometheus on some instances. Maybe it is not an issue.
refactored the code for the naming.
| _GAUGES = {} | ||
|
|
||
|
|
||
| def _get_gauge(name, documentation, label_names): |
There was a problem hiding this comment.
Could mention that it's a multiton pattern.
This helps scanning the intent.
Alternative approach:
registry = CollectorRegistry()
for m in ... :
Gauge(m["name"], ... , registry=reg)The key must be unique per registry, and when not specified, Gauge uses the global default registry.
To use it, I would group the data by metric name.
Benefit
Avoiding race condition and side effects
This is technically not and issue in worker mode as it currently process 1 request at the time, but this is an issue in thread mode. And this will be an issue with the hybrid mode.
There was a problem hiding this comment.
I'll check this later, unless you beat me to it and propose a PR (I will be away next week, I'm not sure of the importance of this for @florentx 's project
| gauge = _get_gauge(name, metric.get("documentation", ""), sorted(labels)) | ||
| if name not in cleared: | ||
| # drop the series that disappeared since the last collection | ||
| gauge.clear() |
There was a problem hiding this comment.
If a metric is missing, it won't be cleared.
This is an issue in a multi-database server:
Metrics available on database A but not on B will still appear on B and not be cleared up.
We should have the clearup at the start, this would also remove the need for the set:
for g in _GAUGES.values():
g.clear()Using a new CollectorRegistry per request solves the issue
|
@gurneyalex OCA/queue#976 may be of interest to you |
3ddc9e8 to
83405f8
Compare
This commit features a refactoring of monitoring_prometheus to get a cron gathering some metrics from the database, and then publishing the result on the /metrics endpoint The new module monitoring_prometheus_queue_job extends the cron to get information about the queue job states.
9b01c0e to
12d19ee
Compare
This commit features a refactoring of monitoring_prometheus to get a cron gathering some metrics from the database, and then publishing the result on the /metrics endpoint
The new module monitoring_prometheus_queue_job extends the cron to get information about the queue job states.