
Build failed - bug fixed
A monitor for InterSystems IRIS. It shows, in one place, the state of an instance right now (Overview),
how it changed over time (History, from the System Monitor ^%SYSMONMGR data in SYS.History), and
what its processes are doing (Processes).

/historymonitor/api/v1, which the interface uses as its only data source.https://github.com/diashenrique/iris-history-monitor/blob/master/https://github.com/diashenrique/iris-history-monitor/blob/master/specs/001-api-v1/contracts/openapi.yaml.| History | Processes |
|---|---|
![]() |
![]() |

Needs IRIS 2026.1 or later (tested on IRIS Community 2026.1) and IPM 0.10.9 or later.
zpm "install iris-history-monitor"
or, from a clone of this repository:
zpm "load /path/to/iris-history-monitor"
The image is published to the GitHub Container Registry on every change to master:
docker run -d --name iris-history-monitor -p 52773:52773 ghcr.io/diashenrique/iris-history-monitor:latest
latest is the newest; each module version also has its own tag (for example :2.1.1). To build it
yourself from a clone:
git clone https://github.com/diashenrique/iris-history-monitor.git
cd iris-history-monitor
docker compose up -d --build
The image installs the module with IPM in its own namespace, IRISMONITOR, and turns history
collection on for itself (the steps in Turning on history collection).
Ports come from .env (IRIS_PORT=52773, IRIS_SUPERSERVER_PORT=1972).
Open http://localhost:52773/historymonitor/index.html and sign in. In the Docker image the user is
_SYSTEM with password SYS; change it before the container is reachable by anyone else. The
Management Portal also gets a favourite, History Monitor, that opens the same page.
To let someone use the monitor without being an administrator, give them the role
HistoryMonitorViewer (created by the install). It allows reading the monitor and nothing else.
History shows what the instance’s own System Monitor records. On a standard IRIS install it records
nothing until an administrator turns it on, and the History page says so. The module never turns it on
by itself.
As an administrator, in a terminal (iris session IRIS -U %SYS):
do ##class(%Monitor.Manager).Activate("%Monitor.System.HistoryPerf")
do ##class(%Monitor.Manager).Activate("%Monitor.System.HistorySys")
do ##class(%Monitor.Manager).StartApp()
The first sample arrives within about 5 minutes.
Keep it running after a restart. IRIS does not start the Application Monitor again when the instance
starts, even with the classes active (measured on IRIS 2026.1). Add a SYSTEM entry to the %ZSTART
routine in %SYS:
%ZSTART ; startup hooks
quit
SYSTEM ; runs when the instance starts
try { do ##class(%Monitor.Manager).StartApp() } catch {}
quit
If the instance already has a %ZSTART, add the StartApp() line to its SYSTEM entry instead of
replacing the routine.
Check. GET /historymonitor/api/v1/history-collection answers "state":"recording", and the notice on
the History page goes away.
How long the instance keeps each granularity (the History page shows it next to the granularity):
| Granularity | Default | Change it (in %SYS) |
|---|---|---|
| 5 minutes | 7 days | do ##class(SYS.History.PerfData).SetPurge(days) |
| Hourly | 60 days | do ##class(SYS.History.Hourly).SetPurge(days) |
| Daily | kept indefinitely | do ##class(SYS.History.Daily).Purge("YYYY-MM-DD") removes older days |
To try the History page before real data builds up, load demo history in %SYS:
zn "%SYS"
do ##class(SYS.History.SysData).Demo(30)
The monitor can show a desktop notification when a metric gets worse (OK to warning, OK to critical,
warning to critical), so you notice a problem without watching the Overview. Turn it on in the header,
Notifications (the bell), then Turn on; the browser asks for permission once. The choice is kept per
browser.
Limits, set by browsers:
localhost. On a plainhttp://server:52773 address the dialog says so and they cannot be turned on.This is a convenience for someone with the monitor open, not unattended alerting. For alerts when nobody is
watching, use the instance’s own tools: System Monitor e-mail alerts (^%SYSMONMGR), or the SAM metrics
(this module also publishes its own sensors) read by an alert manager.
2.0.0 removes the old pages (/csp/irismonitor/*.csp) and the switch that turned the new monitor on.
Install it over 1.x as usual (zpm "install iris-history-monitor" or load):
Old addresses keep working: each one forwards to the matching screen, and they stay that way for all of
2.x.
| Old address | Opens |
|---|---|
dashboard.csp |
Overview |
historylicense.csp, historycspsessions.csp, historydatabase.csp |
History on that metric |
systemprocesses.csp |
Processes |
anything else under /csp/irismonitor/ |
Overview |
The upgrade removes what the old pages left in the module’s namespace: their classes and compiled pages,
their files, and their scratch data (^IRISMonitor). It never deletes a namespace or a database.
The monitor is on for everyone with the HistoryMonitorViewer role. To keep someone out, remove the
role or disable the /historymonitor web application.
src/cls/diashenrique/historymonitor (api, service, util, web). Tests are in .../test; run them in the module’s namespace withdo ##class(%UnitTest.Manager).RunTest("diashenrique/historymonitor/test","/nodelete").web/ (React, TypeScript, Vite). The built files are committed tosrc/web/historymonitor/, so IRIS serves them as static files with no build step on the server.cd web
npm ci
npm test # unit and accessibility tests, fixtures checked against the API contract
npm run build # writes src/web/historymonitor/ (commit the result)
End-to-end tests run the interface against a real IRIS. Start a container with this repository mounted
at /home/irisowner/repo, prepare it, then run Playwright:
export HM_VIEWER_PASSWORD=... HM_NOROLE_PASSWORD=...
.github/ci/e2e-setup.sh
cd web && npm run e2e # HM_BASE_URL, default http://localhost:52773/historymonitor/
Changes follow the spec-driven workflow in https://github.com/diashenrique/iris-history-monitor/blob/master/CLAUDE.md and
https://github.com/diashenrique/iris-history-monitor/blob/master/.specify/memory/constitution.md; specs are in https://github.com/diashenrique/iris-history-monitor/blob/master/specs/.
CI runs the ObjectScript tests, an IPM install check, the interface tests, the end-to-end tests and the
Docker image.
Every API call needs a signed-in user with the HistoryMonitorViewer role (or an administrator).
Errors come back as application/problem+json.
The interface loads nothing from other sites and has no inline script or style, so it runs under a
strict Content-Security-Policy. IRIS does not send one; set it in the web server in front of IRIS, on
the interface’s static files only (index.html and assets/). The IRIS sign-in page uses inline script
and style and would break under it. The end-to-end test
https://github.com/diashenrique/iris-history-monitor/blob/master/web/tests/e2e/csp.spec.ts runs every screen under this policy:
default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'
Apache (with the Web Gateway), mod_headers:
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'"
Nginx, in the server that passes /historymonitor/ to IRIS (repeat the same gateway or proxy
directives inside this location):
location ~ ^/historymonitor/(index\.html|assets/) {
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'" always;
# ... the same proxy_pass / gateway directives as for /historymonitor/
}
Changes per version: https://github.com/diashenrique/iris-history-monitor/blob/master/CHANGELOG.md. How a version is released: https://github.com/diashenrique/iris-history-monitor/blob/master/docs/releasing.md.
MIT.