Skip to main content

The Monitoring page

The Monitoring page is a single scrollable view with five cards. This page walks each one — what every column means, what numbers are healthy, when to act.

Reach the page from the 📊 Monitoring entry in the left sidebar (visible to superusers + roles granted monitoring:view).


At a glance

📊 MonitoringUPTIME14d 03hCONNECTED USERS12HELD LOCKS3POOL CONNECTIONS7 / 20POOLSdefault · postgresql · 5/20 · 15 idle · 0 overflowreporting · postgresql · 2/10 · 8 idle · 0 overflowjdedwards · oracle · 0/5 · not opened (lazy)CONNECTED USERSalice · sid=a8c4d1f2… · client=b7e3…bob · super · sid=c0f3a2b7… · client=—carol · sid=e2a7c5d9… · client=8a1f…HELD LOCKSbob · crm.customers · CUSTOMER_ID=14 · 2 min agoalice · crm.deals · DEAL_ID=88 · 5 min agocarol · crm.activities · ACTIVITY_ID=341 · 12 sec agoLOGS (live)14:02:01.083 INFO liberty.connectors · default pool: 5/2014:02:11.408 WARN liberty.jobs · run_a8c4 retried (1/3)14:02:12.812 INFO liberty.web.screens · user alice opened crm.customers14:02:13.045 INFO liberty.connectors · query customers_get · 42 rows

KPI strip

Four numbers at the top. Each is a quick read on a single dimension:

KPIWhat it countsWhen to worry
UptimeHow long the framework process has been running.If it resets unexpectedly, the framework crashed and restarted (or systemd / Docker re-pulled it). Check the logs around the restart timestamp.
Connected usersSessions currently signed in (have a fresh access token).Normal install: low single digits. A jump (a hundred at once) might mean a load test or a script with a leaked token.
Held locksRow-level locks the framework holds — one per opened edit dialog.If a lock is held for hours and the user has left, the dialog is stale. Either the user reopens and saves/closes, or you can release manually (see Held locks).
Pool connectionsTotal in-use connections across every pool.Should stay well below the sum of pool sizes. If you regularly hit the limit, raise pool sizes or investigate slow queries.

The KPIs refresh every few seconds via the framework's Socket.IO channel — no page reload needed.


Pools

One row per SQL pool the framework knows about. Pool config comes from Settings → Pools; this card is the live view of each.

ColumnNotes
PoolThe pool's name (the key under [pools.*] in the connectors file).
Dialectpostgresql, oracle, mysql, mssql, sqlite, db2 — what SQLAlchemy reports for this engine.
In useConnections currently checked out of the pool by a running query.
IdleConnections that are open but free to serve the next query.
Overflown/max — extra connections beyond pool size, opened temporarily when in-use hits the limit. A persistent non-zero overflow means the pool is under-sized.

A pool shown as not opened (lazy) hasn't been used yet — the engine isn't materialised until the first query hits it. That's normal and saves resources; it doesn't mean misconfiguration.

What to do on a saturated pool

SymptomAction
in use = pool size, overflow growing.Either bump the pool size (Settings → Pools → <pool> → Pool size), or investigate slow queries — a stuck query holds a connection.
Many idle connections.Pool is over-sized; you can shrink it to save DB-side memory. Not urgent.
not opened on a pool that should be active.The connector hasn't been used yet. Open a screen / dashboard that uses it; the pool materialises.

Connected users

One row per currently-signed-in user.

ColumnNotes
UserThe username. Superusers get a super chip.
SessionThe Socket.IO session id (first 8 characters, the rest hidden — abbreviated for legibility).
ClientThe client id from the JWT (also abbreviated). Identifies the browser tab — one user may have multiple sessions across tabs.

The card is the live answer to "who's currently in?" — the framework's user store has timestamps for last sign-in, but this card shows right now.

When to investigate

PatternWhat it usually means
Same user with many sessions.The user has many browser tabs open. Usually harmless.
A user signed in days ago, still listed.Their access token is still valid (the default TTL is 1 hour for the access token, 14 days for the refresh) — they renewed silently. Disabling the user in Settings → Access takes effect on their next refresh.
The list is empty.Nobody is signed in. (Or there's a problem — verify by signing in yourself.)

Held locks

One row per row-level lock the framework is holding. A lock is soft — it doesn't block the database; it blocks the UI. When user A opens row 14 for edit, user B sees the row marked locked and can't open the same edit dialog. The lock is released on dialog close (save or cancel) or after a TTL.

ColumnNotes
UserWho holds the lock.
Record<app>.<screen> · <key>=<value> — which row, on which screen of which app.
SinceHow long the lock has been held. Format: 12 sec ago, 3 min ago.

Released automatically

A lock is released by:

  • The user clicking Save or Cancel on the dialog.
  • The user closing the browser tab (the framework detects the lost Socket.IO connection).
  • The lock TTL expiring (default 1 hour) — the framework drops orphaned locks.

Manual release

For genuinely stuck locks (the user is gone, the lock TTL hasn't fired):

liberty-admin lock release --app crm --screen customers --key CUSTOMER_ID=14

This drops the lock immediately. The next user can open the dialog. Use sparingly — releasing a lock while the original user is mid-edit silently overwrites their work.


Logs (live)

The bottom card streams the framework's last few hundred log lines from the in-memory ring buffer.

ElementWhat it does
TimeServer-side timestamp (HH:MM:SS.mmm).
LevelINFO / WARNING / ERROR / CRITICAL — colour-coded (green / yellow / red / dark red).
NameThe Python logger name (liberty.connectors, liberty.jobs, nomaflow.python, your plugin's logger).
MessageThe log message.

Controls

ControlEffect
PauseStops auto-scroll. Stream continues; you can scroll back without the view jumping. Resume re-engages auto-scroll.
Level filter (All / Info / Warn / Err)Hide lines below the chosen level. Err shows only ERROR + CRITICAL.
Text filterSubstring match on logger name + message. Case-insensitive.
Clear filterResets both filters.
Trash iconEmpties the client-side buffer (the server buffer is untouched — refresh and lines re-arrive).

The stream is client-side bounded at ~1000 lines. Older lines fall off as new ones arrive. For historical logs beyond what the buffer holds, look at the framework's log file on disk (/var/log/liberty/app.log by default, or wherever your logging config points).

Permissions

The log viewer is superuser-only — the framework returns a Log viewer requires superuser access banner if a non-superuser opens the page. Logs frequently contain internal details (SQL fragments, function arguments, user emails) that aren't safe for general operator viewing.


Refresh interval

The page refreshes its data via Socket.IO at these cadences:

CardRefresh trigger
KPIs, Pools, Connected users, Held locksEvery ~5 seconds on a server tick, and immediately on user sign-in / sign-out / dialog open / dialog close events.
LogsPush-based — every log line emitted by the framework streams to the page in real time (subject to the 1000-line client buffer).

No manual reload button — the page is meant to stay open in an operations tab.


What this page is NOT

  • Not a historical view. A process restart wipes Locks, Connected users and the Log buffer. For long-term retention, route logs to an external system + use the framework's audit tables.
  • Not a per-query performance view. For slow-query investigation, enable Postgres' pg_stat_statements or wire an APM.
  • Not a resource usage view. Container CPU / RAM live in docker stats / Portainer / Kubernetes; OS-level metrics live in your monitoring agent.

The Monitoring page answers "what's the framework doing right now?". For "what did it do yesterday?" you need the layers below.


What's next