Configuration
Every setting in Database Health Monitor, and what each one changes.
Thresholds
Every check has a warning and a critical threshold, and a direction — whether a higher reading is worse (database size) or a lower one is (free disk, days until a credential expires).
Set them against your own instance, not against a general idea of big. A 60 GB database is unremarkable on one server and an emergency on another. Run the checks once, look at the readings you actually get, then set thresholds a little above them.
A threshold of 0 on a higher is worse check means "any value at all is a problem", which is right for Scheduled actions failing and wrong for almost everything else.
Retention and windows
| Setting | What it changes |
|---|---|
| Window (minutes) | How far back a counting probe looks — mail failures, server errors |
| Stale after (minutes) | How old a reading may get before it counts as stale |
| Retention (days) | How long readings are kept before the prune job removes them |
| Alert cooldown (hours) | The minimum gap between repeat alerts for one unresolved condition |
Alerting, which is off twice
Nothing is sent until both switches are on:
- the company's master alert switch, and
- the individual check's own Alert on setting.
Two switches rather than one is deliberate: turning the whole thing off during a migration should not require unticking thirteen checks and remembering to put them all back.
Cooldown suppresses repetition, not news
A repeat alert for a condition that is still unresolved waits for the cooldown. An escalation from warning to critical goes out immediately, cooldown or not. The cooldown exists to stop the same message arriving every fifteen minutes, not to delay the news that things got worse.
Acknowledging
Acknowledging an alert clears its cooldown and deliberately does not change the severity. Seeing a problem is not fixing one, and a dashboard that goes green because somebody clicked acknowledge is a dashboard that lies.
Sources — watching your own models
Three checks ship reading unknown by design: integration failures, backlog, and soonest credential expiry. They have no opinion about what matters in your database until you tell them.
A source is:
| Field | Meaning |
|---|---|
| Model | Technical model name, e.g. payment.transaction |
| Kind | Failures and Backlog count records; Expiry date reads a date |
| Domain | A plain Odoo domain, e.g. [('state', '=', 'error')] |
| Expiry field | Required for an expiry source — the Date or Datetime field |
| Note | Why this is worth watching, for whoever is on call at 3am |
The domain is read as data, never evaluated as Python. It is a domain, not an expression, and that is a deliberate limit rather than an oversight.
Write the Note. The person reading the alert is often not the person who configured the source.
The external endpoint
One endpoint record per company, under Database Health → Configuration. Every route is off or minimal by default.
| Switch | What it opens |
|---|---|
| Expose status | GET /technovision/health/status — overall severity and a count |
| Expose details | Adds per-check names and values to that response |
| Expose metrics | GET /technovision/health/metrics — Prometheus text |
| Accept agent reports | POST /technovision/health/report — the only route that writes |
Status returns 503 for critical or unknown, so an uptime checker can work on the status code alone without being given any detail about your instance.
Metrics is off by default because it cannot avoid naming every check. That is fine inside a private network and is not something to expose to the internet.
The token
Generated on the endpoint and shown masked afterwards. It goes in an Authorization: Bearer header and never in a query string — a token in a URL ends up in the web server's access log, the browser history, and every proxy in between.
Rotation keeps the previous token working for a grace period (default in hours), so you can roll the agent and the uptime checker without a gap.
Also on the endpoint: an IP allowlist and a rate limit per minute. Both are worth setting if the route is reachable from outside.
The agent
Free disk, backup age, backup size, filestore size and load average cannot be seen from inside a database session, and this module never runs an operating-system command — giving an ERP process the ability to shell out is a larger problem than not knowing the disk is full.
So a small script you run on the host POSTs them. The accepted fact codes are a fixed list and nothing else is stored:
disk_free_percent disk_free_bytes
backup_age_hours backup_size_bytes
filestore_bytes load_averageUntil an agent reports, those checks read unknown. There is no fallback guess, because a guess about free disk space is worse than an honest gap.