BoxLang 🚀 A New JVM Dynamic Language Learn More...
|:------------------------------------------------------: |
| ⚡︎ 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.
# 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.
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.
| In the bar | In the console |
|---|---|
| Timeline waterfall with zoom and search | Overview, requests and in flight with a live stack |
| Every query with rows, time and the line that ran it | Errors grouped by cause, reports with p50, p95 and p99 |
| Exceptions with BoxLang locations and the Java stack | Query statistics, datasources and a connection test |
| Outgoing HTTP calls | Caches, logs with a live tail, environment |
Messages and timers from lensMessage(), lensMeasure()
| Executors, scheduled tasks, JVM and threads |
| Request, runtime, scopes and BIF panels | Bar 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.
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.
BxLens is free, in production too. BoxLang+ lifts the limits and adds history, actions, many servers and AI.
| Free | BoxLang+ | |
|---|---|---|
| Bar with every tab | Yes | Yes, plus request cost and the slow request sample |
| Console: requests, executors, datasources, logs, environment | Yes, after registration | Yes |
| Requests in memory | Last 25 | As configured |
| Errors, reports | In memory, last hour | Saved to disk, up to 15 days |
| Task actions, cache clear, heap dump, log download, bundle | No | Yes |
| Lensy, AI observability, data functions, many servers | No | Yes |
Compare everything in Free and BoxLang+, or see the plans.
Full documentation lives at bxlens.boxlang.io: configuration, every panel, the BIFs, extending BxLens from your own module, security and troubleshooting.
Bug reports and ideas are welcome at BLMODULES.
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.
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
"I am the way, and the truth, and the life; no one comes to the Father, but by me (JESUS)" Jn 14:1-12
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.
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.rc and prc keys only, never values. Events, views and layouts are also in the Timeline.bar.actions on and a console that is not read only, and are audited. New setting bar.actions.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./shop/index.bxm/users/42).harness/app/shop, WITH_COLDBOX=1) and an e2e spec, ColdBoxSpec.box.json are read.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.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.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.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.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.appActions).watcherActions).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.lensInventory.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.mdlensReport, lensErrors, lensQueries and lensInflight are BoxLang+ onlyLENS_REGISTRATION, a mock registration service (harness/start-mock-registration.sh), an unregistered e2e server and RegisterSpece2e-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.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
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)/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)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 statecollect.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/api/threads and the dump) are admin only, and the settings values of console.access, access.proxyPeers and console.overridesFile are hidden from a viewerlocalhost, 127.0.0.1 and [::1] as Host names unless access.allowedHosts is set (DNS rebinding)/orders/:id); QueryStats keeps SQL without string and number literals; stores trim in batches instead of scanning on every new keyLensConfig resolves paths onceJson.write no longer uses String.formatmavenLocal is searched last, and the bundled bx-ai archive is verified by SHA-256tools/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 modeldocs/assets/lensy.svgdiagnose 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 pageutil/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 loadshistory.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)-Dname=value and --flag=value pairs are masked inside any value; outgoing HTTP URLs are maskedhttp(s) only module links, escaped single quotes in Copy as cURLconsole.actions=false also stops cache clear, evict and reap; the heap dump folder is kept until it is deleted and retriedonORMQuery, 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 ORMIntegrations) 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 IntegrationsFirst release. BxLens is a commercial Ortus Solutions product. Report issues in the BLMODULES Jira project.
/~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, Settingsconfig/bxlens-layout.json (saving needs BoxLang+); Open console button and More menu in the barinfo severity) for missing headers and cookie flagscollect.level (off, light, full) and tabs.hidebx-plus (Plus, Trial, Expired, Free). See the free and Plus split belowdemo-pool, load.bxm, stall.bxm, LENS_LICENSElensMessage, lensDump, lensStart, lensStop, lensMeasure, lensAddMeasure, lensException, lensEnable, lensDisable, lensIsEnabled, lensRender and lensPanel BIFsonLensRegister, onLensCollect, onLensRequestStart, onLensRequestFinishconfig/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 consoleconsole.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.logconsole.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 cycleerrors.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.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 removedconsole.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 schemalensReport(), lensErrors( limit=20 ), lensQueries( limit=20, sort="slowest" ), lensInflight() and lensLicense(). The harness page api/lens.json.bxm shows themcollectors.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/~bxlens/ with a trailing slash opens the console (IndexRewrite.bx). On MiniServer it also needs a pass predicate, see docs/guides/production.mdenabled 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.mdcollectors.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 peeronException, onSOAPRequest, onSOAPResponse), the heap and thread dump BIFs, and the monolithic collector
$
box install bx-lens