BoxLang 🚀 A New JVM Dynamic Language Learn More...

bxLens

v1.0.0-snapshot BoxLang Modules

⚡︎ BoxLang Module: BxLens

|:------------------------------------------------------:  |
| ⚡︎ B o x L a n g ⚡︎
| Dynamic : Modular : Productive
|:------------------------------------------------------:  |
Copyright Since 2023 by Ortus Solutions, Corp
www.boxlang.io | www.ortussolutions.com

 

See what your BoxLang application is really doing. BxLens adds a debug bar to every page and a console for the whole server. Find the slow query, the N+1 loop, the failing call and the starved thread in seconds, without leaving the browser and without sending your data anywhere.

Why BxLens

  • A bar on every page. A timeline of templates, functions, queries, HTTP calls and transactions for the request you just made. Click a line to open the file in your editor.
  • A console for the server. Live requests, errors grouped by cause, query statistics, datasources, caches, logs, executors, scheduled tasks, JVM numbers and threads.
  • Lensy, the Box Agent for your server. Ask what is slow in plain words. Lensy reads the same data you see and can run approved actions.
  • Private by design. Everything is collected in memory by Java code inside your server. The console makes no calls to other sites and works air gapped. The only request BxLens ever makes is the one time registration form.
  • Built with BoxLang. Works with the MiniServer, CommandBox and servlet deployments.

Install

# OS binary
install-bx-module bx-lens

# CommandBox
box install bx-lens

BxLens is off by default. Turn on the bar and the console in boxlang.json:

{
	"modules": {
		"bxLens": {
			"settings": {
				"bar": { "enabled": true },
				"console": { "enabled": true, "password": "bxsecret:..." }
			}
		}
	}
}

Make the password with boxlang generatesecret "your password". The console is at /~bxlens/index.bxm. Both default to loopback only. Keep the bar off on live servers and read Running BxLens in production before you expose the console.

Registration

The debug bar needs no registration. The console needs a free, one time registration per server: open it, fill in the short form, paste the key that arrives by email, and you are in. The key is checked offline and tied to the server name. Containers pin a name with LENS_SERVER_NAME. Registering starts a 14 day trial of the BoxLang+ features. Servers with BoxLang+ need no registration. See Registration and the privacy notice.

What you get

In the bar In the console
Timeline waterfall with zoom and searchOverview, requests and in flight with a live stack
Every query with rows, time and the line that ran itErrors grouped by cause, reports with p50, p95 and p99
Exceptions with BoxLang locations and the Java stackQuery statistics, datasources and a connection test
Outgoing HTTP callsCaches, logs with a live tail, environment
Messages and timers from lensMessage(), lensMeasure() Executors, scheduled tasks, JVM and threads
Request, runtime, scopes and BIF panelsBar designer, settings, audit log, roles
Your own panels with lensPanel() Lensy, AI observability, mail and ORM pages

The full list is in Features. A health strip turns amber or red when something is wrong, and the keyboard works everywhere: Ctrl+` toggles the bar, 1 to 9 switch tabs, / searches.

Send things to the bar

lensMessage( "Loaded #orders.len()# orders", "info" );
lensDump( order, "order after pricing" );

orders = lensMeasure( "load orders", () => orderService.list() );

lensPanel( "orm", "ORM" ).columns( [ "Entity", "ms" ] ).rows( rows ).badge( rows.len(), "none" );

BoxLang+ also adds data functions (lensReport(), lensErrors(), lensQueries(), lensInflight()) that return the console data as plain structs. See the BIF reference.

Free and BoxLang+

BxLens is free, in production too. BoxLang+ lifts the limits and adds history, actions, many servers and AI.

Free BoxLang+
Bar with every tabYesYes, plus request cost and the slow request sample
Console: requests, executors, datasources, logs, environmentYes, after registrationYes
Requests in memoryLast 25As configured
Errors, reportsIn memory, last hourSaved to disk, up to 15 days
Task actions, cache clear, heap dump, log download, bundleNoYes
Lensy, AI observability, data functions, many serversNoYes

Compare everything in Free and BoxLang+, or see the plans.

Documentation

Full documentation lives at bxlens.boxlang.io: configuration, every panel, the BIFs, extending BxLens from your own module, security and troubleshooting.

Contributing

Bug reports and ideas are welcome at BLMODULES.

License

BxLens is a product of Ortus Solutions. License terms apply, see the BoxLang+ plans page and Licensing. BoxLang+ or a trial unlocks the items marked BoxLang+ above. This may change. Phosphor Icons are MIT licensed, see src/main/bx/assets/ICONS-LICENSE.txt.

Ortus Sponsors

BoxLang is a professional open-source project and it is completely funded by the community and Ortus Solutions, Corp. Ortus Patreons get many benefits like a cfcasts account, a FORGEBOX Pro account and so much more. If you are interested in becoming a sponsor, please visit our patronage page: https://patreon.com/ortussolutions

THE DAILY BREAD

"I am the way, and the truth, and the life; no one comes to the Father, but by me (JESUS)" Jn 14:1-12

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.


[Unreleased]

Added (ColdBox support)

  • BxLens finds a ColdBox application (application.cbController) and registers one interceptor of its own in it, so nothing in the application changes. A new controller after ?fwreinit is noticed on the next request. Setting collectors.coldbox.enabled (default true; it does nothing until a ColdBox application is found), maxEvents and maxViews.
  • A ColdBox tab in the bar: the route, event, handler, layout and view, the number of events, views (and how many were different) and layouts, views rendered more than once, the time of each event, view and layout in a waterfall (layouts wrap their views, indent stops after five levels), and the state of the event cache (hit, miss or not cacheable, from the handler metadata). Names of rc and prc keys only, never values. Events, views and layouts are also in the Timeline.
  • Buttons in the bar, free: Clear event cache, Clear view cache and Reinit framework. A reinit password goes from the browser to the application, never through BxLens. The buttons need the token the page carries, a same site request, bar.actions on and a console that is not read only, and are audited. New setting bar.actions.
  • Request tags: the BIFs lensTag( name ) and lensFramework( name, version ), and data.lens.tag() and data.lens.framework() in onLensCollect. A tag is 1 to 24 characters of a-z 0-9 : _ -, at most 8 per request. ColdBox requests are tagged coldbox.
  • Console Requests: a Tags column and a tag filter, an Event column and a cache hit mark for ColdBox requests, a ColdBox block in the request detail, and the ColdBox version on the Applications page. The URL of an application that routes by path now includes the path (/shop/index.bxm/users/42).
  • Harness: a small ColdBox application (harness/app/shop, WITH_COLDBOX=1) and an e2e spec, ColdBoxSpec.
  • A ColdBox page in the console: overview (version, environment, what the application is made of, the settings that matter for speed), composition (routes, handlers, interceptors, layouts), modules (a timeline of activation times, a tree, a table and a Resolution view that finds the same module on disk in more than one version and shows which copy ColdBox loaded), CacheBox caches (same layout as the Caches page; evict, reap and clear are BoxLang+) and executors. Names, counts and times only. Only the name, slug and version of a box.json are read.
  • Task groups and meta on the Tasks page (free): a Groups row as a tree (billing/invoices sits under billing) with an Ungrouped bucket, a By scheduler / By group switch, a Meta block in the detail (secret-looking keys masked) and a strip of the next runs.
  • A Schedulers tab on the ColdBox page: the ColdBox schedulers and tasks with groups, meta and next runs (free), and Run now, Pause, Resume and Remove (BoxLang+, audited). BxLens now calls ColdBox in the context of the application, so ColdBox can load its own classes.
  • The ColdBox Advisor (free): fixed rules over data BxLens already has. In the bar, findings for the request (a view rendered more than once, a request slow for its own event). In the console, a Findings tab and a count: reinit open in production, development settings in production, no error handling, cbdebugger in production, a module in more than one version or bundled twice, a module nested too deep or slow to start, failing, late or paused tasks, a saturated executor, a cache under pressure, a cacheable event that never hits. Per event statistics (requests, errors, p50, p95, event cache hits) since the server started.
  • Lensy gets 12 ColdBox tools: nine to read (coldboxApp, coldboxAdvice, coldboxEvents, coldboxRequest, coldboxComposition, coldboxModules, coldboxSchedulers, coldboxCaches, coldboxExecutors) and three actions that need an approval (coldboxTaskAction, coldboxCacheAction, coldboxReinit, which only works when the application has no reinit password). Find solution (BoxLang+) asks Lensy to write one prompt for a coding agent from a finding, on demand only. Copy prompt is free. Ask Lensy buttons on the tabs and in the bar.
  • Run your own model: the Ollama guide is now a full guide (docs/guides/ollama.md): what Lensy needs from a model, Ollama, Docker Compose (tools/ai/docker-compose.ollama.yml, with a healthcheck so the models are pulled when the server is up), Docker Model Runner, an OpenAI compatible server, a hosted provider, security, troubleshooting. A Run your own model card in Settings, Assistant, with a tab per way, a snippet to copy and Use these settings, which fills the form without saving. A hint under a failed Test connection. A smoke test (tools/ai/smoke.bxs, a BoxLang script) that asks six fixed questions through the console and checks the tool calls, the tool limit, the time and the answer, and denies the approval card. The table of tested models lists only models that passed it: none yet.
  • Fix: Lensy had no tools on a server with bx-compat-cfml, which every ColdBox application on BoxLang has: that module gives a function the CFML shape of metadata, so aiToolRegistry().scanClass found no @AITool. Lensy now reads the metadata itself when the scan finds nothing (models/ops/Lensy.bx). An e2e test covers it on the ColdBox server.
  • Help icons and a Glossary (free): an i next to the terms that assume knowledge (p50, p90, p95, p99, average, error rate, throughput, hit ratio, event cache, view rendered more than once, N+1, in flight, executor, task group, module resolution and more), in the bar and in the console, opening a card from one glossary file (glossary.json). A Glossary page in the console with a search box, and a page in the docs generated from the same file (tools/docs/glossary.bxs). A test fails when a page names a term that does not exist.
  • Reports boards (free): a Boards view on the Reports page with ranked lists, Global (by URL) and ColdBox (by event, view, layout, CacheBox and task group): highest error rate, slowest p95, slowest requests, where the time goes, most queries per request, most exceptions, cache effectiveness, views and layouts, tasks. Each row says why it ranks and has Open evidence, Copy prompt (free) and Find solution (BoxLang+). The numbers are those of this run on this server. Per URL latency buckets and query counts are now kept for this run.

Added (applications and watchers)

  • Console Applications page: every application the runtime has started, with state, uptime, sessions (a count), and for each one its tasks, watchers and class loaders. Restart (shuts the application down, BoxLang starts it again on its next request, you type the name to confirm) and Remove (an expired entry) need BoxLang+ (appActions).
  • Console Watchers page: every file watcher in the runtime with its owner (an application or global), state, paths and settings. Start, stop and restart need BoxLang+ (watcherActions).
  • The bar Runtime panel names the other applications of the runtime and links to the Applications page.
  • Lensy: the tools applications and watchers, and appAction and watcherAction, which wait for your approval. The tool count limit in the catalog test went from 40 to 45.
  • Both pages work for another server through its health snapshot (BoxLang+, read only). The demo harness has a second application, lensInventory.

Added (registration)

  • Registration modes. The debug bar works without registration. The console on Free and Trial needs a one-time free registration per server, shown before the sign in: a key is emailed, pasted back and checked offline (Ed25519), tied to the server name. Containers pin a name with LENS_SERVER_NAME and pass the key with registration.key or registration.keyEnv. BoxLang+ licensed servers need none. Registration includes a 14 day trial (one per email) and caps bx-plus trials at that length. The only outbound request is the registration form (registration.endpoint). Privacy notice in docs/privacy.md, see docs/console/register.md
  • The data functions lensReport, lensErrors, lensQueries and lensInflight are BoxLang+ only
  • Harness: LENS_REGISTRATION, a mock registration service (harness/start-mock-registration.sh), an unregistered e2e server and RegisterSpec

Changed

  • The end to end suite is now BoxLang: TestBox specs driving bx-playwright (e2e-bx/), 322 tests ported one to one from the Node Playwright suite. The mock model (harness/mock-ai) is BoxLang too. The Node suite and the Python mock are gone. CI starts the servers with e2e-bx/servers.sh and runs e2e-bx/run.sh.

Fixed

  • The mail preview now blocks remote content. The sandboxed frame had no Content-Security-Policy, so a remote image or tracking pixel in a received message loaded when an admin opened it. The frame now allows only inline images and styles.

Added

  • The docs publish from development and main in two versions kept the same for now: 1.0.0 at the site root and next at /next/ (tools/docs/sync-version.sh, versions.default). The end to end job builds bx-mail from its events branch, and VolumeData.volumeOf now matches mounts with either separator, which fixes VolumeDataTest on Windows

  • A custom docs theme and homepage for bxlens.boxlang.io (docs/.theme), the docs.yml workflow that builds the site with bxSites and publishes it to gh-pages, and tools/videos: a recording script and a narration script for each major area of Lens. See docs/project/docs-site.md

  • The docs homepage hero is an animated GIF in the bxSites image gallery, with a 52 second trailer (tools/videos/trailer, original upbeat music), a Gallery page, a large Lensy section with clips, and a clear note that multi server observability is BoxLang+ and Free is one server only. The module workflows no longer run for docs only changes

  • Free and BoxLang+: a side by side comparison table, why Plus is worth it and how to activate it (bx-plus, boxlang module:plus activate), on the Licensing page and in the readme.

  • AI observability docs: screenshots of every AI tab and the limits written out (no counters per middleware, the flight recorder is listed and not replayed, tokens are never estimated).

  • The store: one owner (StoreService) behind a PersistentStore interface writes all saved data on its own thread. Each server writes its own subfolder of store.dir (named by store.instanceFolder, LENS_INSTANCE or the host name), so many servers can share one volume. Streams are JSON Lines, one file per UTC day. Retention is store.retentionDays (15, 30 at most) and store.maxMB caps the whole folder. A heartbeat in instance.json detects two live servers using one name, and folders of servers that stopped writing are removed. Lens warns when the folder is on a container's own file system. See docs/reference/store.md

  • The HTTP page (Inspect group): every outgoing call counted by host and endpoint with the status mix, p50, p95 and p99 from a mergeable latency histogram, what needs attention (hosts with errors or timeouts, slow hosts, endpoints that answer 5xx, large responses and loops of the same call), and with BoxLang+ ranges of 24 hours to 15 days from saved rollups and the list of calls. Calls made outside a request (tasks, threads) are counted too. Paths are patterns (:id), and query strings, headers and bodies are never kept. New limits in collectors.http: slowMs, errorPct, minCalls, repeat, largeMB

  • The server selector (BoxLang+): the HTTP and Reports pages can show another server of the same store folder, or all of them added up. New Plus features servers and httpCalls

  • Reports and Errors follow the server selector in full: another server shows the same page from its saved totals (with p95 merged from latency counts), and All adds servers up and merges error groups with one fingerprint

  • Lensy settings moved into Settings as the Assistant tab. The separate Lensy page is gone from the menu (#ai still opens it)

  • The AI page (Modules group): what the agents, models and MCP servers of bx-ai are doing. A global dashboard (runs, success, run time, tokens, cost, what needs attention, hosted MCP servers), an Agents dashboard with a mini report for each agent and, for one agent, its composition diagram, runs, tools and parts, middleware (with the flight recorder) and instructions with versions; an MCP page for the servers you host (and a page for each one with what failed and what to check); Models, Cost from your own price table, Runs with a step by step trace, Registries and Settings. It is an integration (collectors.aiobs.enabled, opt in) and a BoxLang+ page, with three counters on Free. Lens attaches a passive recorder middleware to each agent as it is created. See docs/console/ai-observability.md

  • The Storage tab in Settings (admin): store state, folder, disk used per server, written / dropped / failed counts, container and folder warnings, and live store.retentionDays, store.maxMB and store.staleAfterHours. New route GET /api/store (admin)

  • Menu groups: HTTP joins Inspect, Modules and ORM move to a Modules group, and the bar designer, Lensy and Settings are the BxLens group. The AI page is now called Lensy

Changed

  • Lensy's MCP calls now go through the MCP client of bx-ai instead of a client written in Lens (about 350 lines of Java removed from the module). Lens sets the controls bx-ai gained for this (an address guard that runs before every request, no redirects, an answer size limit, the MCP handshake, the timeout in milliseconds), so the rules stay the same: public addresses only, checked again before every connection, no redirects, no credentials, the Toolbox gate and the 12,000 character cap. The bundled bx-ai is now the 3.6.0 snapshot build of bx-ai, downloaded by the build (it cannot be pinned by a checksum) until a bx-ai release has these controls. A server that sends its tools in pages is read page by page (up to five pages, 100 tools). What changes for people: a connection test or a chat that meets a server that does not answer can take up to twice the time limit, because the handshake and the call each wait up to the limit. Calls to a server are measured in whole seconds
  • store.retentionHours is replaced by store.retentionDays (an older setting still counts), store.maxMB now limits the whole folder (default 500, was 50 for one file), and errors.json and reports.json moved into this server's subfolder (older files are moved at the first start)
  • The assistant is now called Lensy, the Box Agent for your BoxLang server, everywhere you can see it: the drawer, the button, the AI and Ask Lens pages, the system prompt and the docs. Only text changed: the routes (/api/agent/*), the settings (ai.*) and the audit event names (ai.tool, ai.act, ai.chat...) stay as they were. The audit line of a denied call now reads "Lensy is a BoxLang+ feature" where it said "The assistant". The BoxLang classes are models/ops/Lensy.bx and LensyTools.bx (were OpsAgent.bx, LensTools.bx)
  • The ORM integration replaced the first ORM spike: the JDK proxy around the Hibernate connection provider, the swap of a private Hibernate field, the Logback fallback on org.hibernate.SQL and the reading of Hibernate statistics by reflection are gone. collectors.orm.statistics is removed (Lens no longer forces Hibernate statistics on; use generateStatistics in ormSettings). The console ORM page is always listed so it can show the integration state
  • Defaults: collect.level is light, history.trackNonHtml is off in light and on in full, collectors.queries.includeParams is false everywhere, collectors.orm.enabled is false and Lens registers no ORM listener while it is off or bx-orm is not installed. collectors.bifs and collectors.logs stay off. Light also skips the caller lookup of HTTP calls and transactions and the BoxLang frames of exceptions
  • Viewer role: the Logs (list, read, search), Environment, System and Threads pages and routes (including /api/threads and the dump) are admin only, and the settings values of console.access, access.proxyPeers and console.overridesFile are hidden from a viewer
  • A local only guard accepts only localhost, 127.0.0.1 and [::1] as Host names unless access.allowedHosts is set (DNS rebinding)
  • The snapshot JSON of a request is built when first needed (the bar is rendered for an allowed caller, or the console opens the request), not for every request. A request that is not kept in the history skips issue analysis, header capture and the snapshot collectors. The bar insert looks only at the last kilobyte of the page
  • Request ids are short counter and time based ids, not random UUIDs
  • Reports key URLs with numeric and UUID path segments collapsed (/orders/:id); QueryStats keeps SQL without string and number literals; stores trim in batches instead of scanning on every new key
  • The module list, JVM facts and cache configuration are cached instead of rebuilt for every request; LensConfig resolves paths once
  • Hand written scanners replace regular expressions in the query, error, statistics, secret and JSON code, and Json.write no longer uses String.format
  • Test dependency versions are pinned, mavenLocal is searched last, and the bundled bx-ai archive is verified by SHA-256

Added

  • Lensy can ask MCP servers (BoxLang+). The AI page lists the eleven Ortus documentation servers (BoxLang, ColdBox, CommandBox, TestBox, WireBox, LogBox, CacheBox, ContentBox, qb, Quick, cbauth), all off, and lets the admin add servers of their own and tick which tools Lensy may use. A server's tools are found with tools/list (10 seconds, kept 5 minutes) and named server.tool (server__tool for the model). Every call goes through the Toolbox: role, enabled and ticked, arguments, limits, redaction and the 12,000 character cap, an ai.mcp audit line, and for a custom server your click each time unless it is marked trusted, read only. Addresses are checked on the server (https, no credentials, public addresses only, resolved again before each connection, no redirects). No authentication headers in this version. New routes ai/mcp, ai/mcp/{id}/enable, ai/mcp/{id}/test, audit ai.mcp.change, a BoxLang mock of the servers in harness/mock-mcp. See Servers Lensy can ask and the threat model
  • Lensy, the Box Agent for your BoxLang server, has a face: a boxy cube with a lens for an eye in the button, the drawer, the AI page and the bar's Ask link. It looks idle, thinking (a slow blink and a small wiggle, still with reduced motion), happy after an answer and worried after an error. docs/assets/lensy.svg
  • Lensy (first step of the bx-ai integration, BoxLang+): a chat in a drawer on every console page and on the Ask Lens page, with 32 tools (requests, errors, queries, executors with pool recommendations, threads, blocked threads and deadlocks, GC pressure, datasources, logs, database metadata, a diagnose health sweep and a search of the bundled docs) behind one gate (ops/Toolbox: role, BoxLang+, read only, arguments, redaction, caps, audit). Actions wait for an Approve click held on the server for five minutes. Streaming answers over server sent events, per session memory in the JVM, ai.maxConcurrentChats, ai.maxToolCalls, ai.timeoutSeconds. The AI page (status, live settings, connection test), the bar's Ask link, agent/* and ai/config routes, a mock Ollama for tests (harness/mock-ai). New settings ai.baseUrl, ai.embeddingModel, ai.temperature, ai.timeoutSeconds, ai.maxToolCalls, ai.memoryMessages, ai.maxConcurrentChats, ai.actions, ai.rag, ai.apiKeyEnv; the ai.* settings except the key are now live. Defaults changed to Ollama, llama3.2 and http://localhost:11434. See the AI page
  • Server identity on every record: util/ServerIdentity detects the host name, primary address, all addresses and an instance id once at start (refreshed every five minutes, never per request). New settings server.name, server.address, server.id (also LENS_SERVER_NAME, LENS_SERVER_ADDRESS, LENS_SERVER_ID) and history.serverHeader (X-BxLens-Server). Requests (summary, detail, bar Request tab, console Requests table when more than one server id was seen, exports), error groups and samples, reports, query statistics, in flight entries, the audit log (server=<id>), errors.json and reports.json (top level server, serverId per record) and the BIFs (lensServer(), server in lensReport() and lensDiagnostics(), serverId in the rows of lensErrors(), lensQueries() and lensInflight()). errors.json is now { server, groups }; the older plain list still loads
  • history.headerAlways (default true): the request id header on every tracked request. The id is also request.bxlens.id, lensRequestId() and the logging context key requestId. collectors.http.propagateId (default false, needs a core hook that does not exist yet)
  • Shared secret-name matcher (adds key, pass, pin, cvv, jwt, auth, session, csrf, webhook, dsn, sk_, cardnumber, x-api-key, accesstoken, clientsecret, trustStorePassword, sslpassword) used by the settings, JVM flags, datasource URLs, task definitions and headers; -Dname=value and --flag=value pairs are masked inside any value; outgoing HTTP URLs are masked
  • Query strings are masked in the snapshot, the history summary and the in-flight list
  • Editor link scheme allowlist (server and Settings page), http(s) only module links, escaped single quotes in Copy as cURL
  • Audit lines for refusals and for log and environment reads; every audit field is sanitized
  • Logs: reads from the end of the file, 8 MB scan window, two reads at once (429 when busy)
  • ORM integration: Lens listens to bx-orm events only (see Added below). No class of another module is reflected into for SQL, the Hikari metrics tracker is removed at shutdown
  • A request older than ten minutes is dropped from the in-flight list

Fixed

  • A viewer sign in no longer clears the admin failure counter; IPv6 clients are counted by /64; the stream no longer refreshes the session and its limit check is atomic
  • A proxy header value that is not an IP address is ignored
  • The AI call has its own bounded pool and is cancelled on timeout; the AI context carries no URLs, query strings or literals; console.actions=false also stops cache clear, evict and reap; the heap dump folder is kept until it is deleted and retried

Added (earlier in this release)

  • ORM support for bx-orm, as the first integration. Lens listens to the onORMQuery, onORMFlush and onORMException events of bx-orm 1.7.2 or later. Each statement is a query span and a query entry labelled ORM with its kind (select, insert, update, delete, ddl, other), shown in the bar, the request, the Timeline and the console Queries page (free). Startup DDL and failed statements are included; a statement outside a request counts in the ORM totals only; parameter values need announceQueryParams in the ORM app and collectors.queries.includeParams. The console ORM page (BoxLang+, feature ormStats) shows the integration state, per datasource totals from the events (statements by kind, failures, flushes), the recent failures and the Hibernate statistics read through ORMService.getStatistics; when statistics are off it says so, and an admin can switch them with ORMService.setStatisticsEnabled (audited, refused in read-only mode). Harness: WITH_ORM=1 installs bx-orm 1.7.2-snapshot (BX_ORM_VERSION) or builds it from a checkout (BX_ORM_DIR). See ORM
  • Integrations: a small registry (Integrations) of module integrations with the status notInstalled, available or on. Every integration is opt in (collectors.<id>.enabled, default false), needs its module installed and listens to events only. The console Modules page has an Integrations section with a live, admin only switch that is offered only when the module is installed; routes GET /api/integrations and POST /api/integrations/{id}. Listeners register and unregister without a restart when the setting changes or the module loads (postModuleLoad) or unloads (postModuleUnload). See Integrations
  • The Queries console page shows an ORM label and the kind of ORM statements, and counts a failed ORM statement as a failure

[1.0.0] - 2026-10-08

First release. BxLens is a commercial Ortus Solutions product. Report issues in the BLMODULES Jira project.

Added

  • Standalone console at /~bxlens/index.bxm: password login (bxsecret: value), in-memory sessions, CSRF token, per-IP lockout, strict Content-Security-Policy, no external requests. Pages: Overview, Requests, Executors, Tasks, System, Threads, Bar designer, Settings
  • Executors page with live health reports and thresholds, Tasks page with status and metrics (Run now, pause, resume and reload need BoxLang+), System and Threads pages with a thread dump download (free)
  • Server-Sent Events stream for live console data, with polling as the fallback
  • Bar designer: toggle and reorder bar tabs, saved to config/bxlens-layout.json (saving needs BoxLang+); Open console button and More menu in the bar
  • Request cost (CPU time and bytes allocated, BoxLang+), response headers in the Request panel, slow request sample that names the template and line (BoxLang+), security Notes (info severity) for missing headers and cookie flags
  • collect.level (off, light, full) and tabs.hide
  • License detection through bx-plus (Plus, Trial, Expired, Free). See the free and Plus split below
  • Phosphor icons (MIT) vendored in place of ad hoc glyphs
  • Harness: console password, tasks, demo-pool, load.bxm, stall.bxm, LENS_LICENSE
  • Rewritten core: typed per request model, bounded in-memory request history, access guard (loopback and private networks by default), server side redaction
  • Java collectors for templates, functions, queries (N+1 and slow detection), outgoing HTTP, exceptions, transactions, logs, scopes, runtime, BoxCache statistics and loaded modules
  • Alpine.js UI injected at the end of HTML responses: health strip, Issues, unified waterfall with zoom, filters, search and editor links, History for HTML, JSON and SSE requests
  • lensMessage, lensDump, lensStart, lensStop, lensMeasure, lensAddMeasure, lensException, lensEnable, lensDisable, lensIsEnabled, lensRender and lensPanel BIFs
  • Extension API for applications and modules: onLensRegister, onLensCollect, onLensRequestStart, onLensRequestFinish
  • Live settings: the console Settings page is editable. Changes apply at once, are saved to config/bxlens-settings.json (or console.overridesFile), survive restarts and win over boxlang.json, with a reset per setting. SettingsRegistry defines which settings are live. console.readOnly refuses every change from the console
  • Roles and access: console.viewerPassword for a view-only role (no changes, no download of thread dumps, heap dumps, log files or the bundle, no cache values). access.trustProxyHeader, access.proxyHeader and access.proxyPeers read the client address from a proxy header only from a trusted peer, and never let a remote peer claim loopback. console.requireHttps and a warning banner for plain HTTP. An audit log, bxlens-audit.log
  • Console pages: Datasources (Hikari pool numbers, timings, connection test), Caches (statistics, key list capped at 100, value view cut at 2 KB, evict, reap and clear need BoxLang+), Logs (all files in the logs directory, search, level filter, live tail, path checks, admin download needs BoxLang+), Environment (configuration, modules, JVM arguments, variables, properties, secrets hidden), with a diagnostic bundle zip (BoxLang+), In flight (running requests with a live stack), Queries (per statement runs, average, maximum, total, failures, slow), Errors (grouped by fingerprint, redacted samples), Reports (totals, p50, p95 and p99, status classes, URLs, minute series) and Ask Lens
  • System page: Run GC, heap dump (BoxLang+, console.allowHeapDump, admin only, confirmation, disk space check, one at a time, removed after download or after 10 minutes) and a deadlock banner that shows the cycle
  • Free and BoxLang+ split. Free keeps the bar and most of the console. BoxLang+ or a trial adds request cost and the slow request sample, task actions, cache value, evict, reap and clear, log download, the diagnostic bundle, heap dumps, saving or resetting a bar layout, AI calls from the server, the disk store (errors.json and reports.json saved atomically, totals since first install, a longer minute series; store.enabled, store.dir, store.retentionHours, store.maxMB, store.flushSeconds) and a request history longer than 25. A locked item shows a "BoxLang+" note and the server answers 403 (AI answers 409). The split is the current state and may change.
  • Optional AI help (ai.*): copy a redacted prompt, open ChatGPT or Claude (copies the prompt, sends nothing from the server), and Explain with AI and Ask Lens through the bx-ai module. bx-ai 3.4.0 ships inside the module in modules/bxai and is downloaded by the build (downloadBxAi). Checked with a mock Ollama server (harness/mock-ai). Lens still loads if it is removed
  • New settings: console.viewerPassword, console.requireHttps, console.readOnly, console.overridesFile, console.allowHeapDump, access.trustProxyHeader, access.proxyHeader, access.proxyPeers, store.*, ai.*, and collectors datasources, caches, logfiles, environment, queries, inflight, errors, reports and ask. checks.* and dev.* are now declared in the schema
  • BIFs that return the console data as plain structs and arrays, in any request: lensReport(), lensErrors( limit=20 ), lensQueries( limit=20, sort="slowest" ), lensInflight() and lensLicense(). The harness page api/lens.json.bxm shows them
  • BIFs tab in the bar and the collectors.bifs collector: calls, total, average and slowest time and errors per built-in function, from postBIFInvocation and onBIFException. Heavy and off by default, because every BIF call allocates an event while it is on. Lens's own lens* functions are left out, a request keeps up to 300 names and the list shows the top 60 by total time. Needs a BoxLang build with core pull request 657
  • Modules page in the console: every loaded module, nested ones included, with version, state, author, activation time, path, public mapping, parent, dependencies and what it provides
  • /~bxlens/ with a trailing slash opens the console (IndexRewrite.bx). On MiniServer it also needs a pass predicate, see docs/guides/production.md
  • Demo harness app, Playwright end to end suite, documentation site built with bx-sites

Changed

  • Breaking: enabled is now bar.enabled. access.allowedIPs and access.allowPrivateNetworks are now bar.access (use the word private). The default is loopback only. See docs/configuration.md
  • BxLens is a product of Ortus Solutions under the BoxLang+ proprietary license (freeware with limits) and no longer described as open source. New Java files carry the four line BoxLang+ header
  • The queries collector id and the console Queries page share collectors.queries.enabled. The logs collector (per request) is separate from logfiles (the console Logs page)
  • X-Forwarded-Proto is believed only from a trusted proxy peer
  • Built against BoxLang 1.19, Alpine.js 3.17, Gradle plugins and GitHub Actions updated
  • Lens is disabled by default

Removed

  • Events that do not exist in core (onException, onSOAPRequest, onSOAPResponse), the heap and thread dump BIFs, and the monolithic collector

Fixed

  • The module did not compile, never registered its collectors and read event keys core does not send

$ box install bx-lens

No collaborators yet.
     
  • {{ getFullDate("2026-10-15T20:36:42Z") }}
  • {{ getFullDate("2026-10-15T20:36:43Z") }}
  • 37
  • 11