Integrations
Integrations
An integration lets Lens show what another module reports, for example the SQL of bx-orm. Every integration follows the same rules.
- Opt in, off by default. The setting
collectors.<id>.enabledisfalseuntil an admin turns it on. - The module must be installed. Until it is, Lens registers no listener and offers no switch. The console says "Install
to enable". - Events only. Lens listens to the events the module announces. It never reflects into another module's classes when events exist. If a module offers a documented service call for tools (bx-orm's
ORMService.getStatistics), Lens may call that, reflectively because the module has its own class loader, and has no dependency on the module. - No restart. The setting is live, and a module that is installed later starts to be heard when it finishes loading.
The status
| Status | Meaning |
|---|---|
notInstalled | The module is not loaded. No switch. |
available | Installed, switched off. No listener. |
on | Installed and switched on. The listeners are registered. |
The console lists every integration in the Integrations section at the top of the Modules page, with its status and a switch that is offered only when the module is installed (admin only, live, audited as integration.change). The page of the integration (for example ORM) shows the same status.
The server enforces the rules: POST /api/integrations/{id} answers 409 when the module is not installed, 403 for a viewer, in read-only mode (console.readOnly) and without the CSRF token, and 404 for an unknown id.
Current integrations
| Id | Module (as listed on the Modules page) | Setting | Listens to |
|---|---|---|---|
orm | orm (bx-orm 1.7.2 or later) | collectors.orm.enabled | onORMQuery, onORMFlush, onORMException |
aiobs | bxai (bx-ai, which ships with BxLens) | collectors.aiobs.enabled | The events of bx-ai for agent runs, models, tokens, tools, MCP (both sides), searches, speech, images and embeddings. See AI. |
mail | mail (bx-mail, with the onMail events) | collectors.mail.enabled | onMailInvocation, onMailSpooled, onMailSent, onMailError, onMailBounce, onMailSpoolRun. See Mail. The spool is read through the cache service (mailUnsent, mailBounced) and the settings through the module service. |
The aiobs integration goes beyond events in three places, all behind one BoxLang class (models/aiobs/AiBridge.bx) that catches every error: it reads what an agent is made of (agent.getConfig()), the registries and the statistics of the MCP servers hosted here, and it attaches a passive middleware (LensRecorder) to each agent as it is created, because bx-ai announces nothing when a tool or an agent run throws.
Adding an integration
- Describe it in
Integrations.ALL(Integrations.java): an id, a display name, the module name the module registers under (themoduleNameof itsbox.json, as the Modules page shows it), what to install and a one line description. - Write the collector in
interceptors/collectors/. ExtendBaseCollector, give it@InterceptionPointmethods named like the events, return the integration id fromintegration()and the same id fromid(), and returnfalsefromenabledByDefault().LensService.reconcileCollectorsregisters a collector with an integration only whileIntegrations.on( id )is true, and removes it when the setting is switched off or the module goes away. A new module event (postModuleLoad,postModuleUnload) already triggers that, so nothing else is needed. - Add it to the builtins in
LensService.builtIns(). The id gets itscollectors.<id>.enabledsetting inSettingsRegistry(live, defaultfalse) from the collector list. Declare<id> : { enabled : false }inModuleConfig.bxand add the row todocs/configuration.md. - Count and store with bounds. Per request data goes into
LensRequest(spans,queriesand so on). Totals across requests go into a bounded store likeOrmTotals. Never keep parameter values, and redact before storing. - Show it. Add the page or section to
console.htmlandconsole.js. If the page is gated, add the feature toLicensing.PLUS_FEATURES. The integration list and its switch need no new code. - Test it. Unit tests drive the collector with fake events (see
OrmCollectorTest), the status logic needs no module (IntegrationsTestpasses a fake "installed" answer), and a Playwright test covers the page on a harness server with the module and on one without (orm.spec.ts,free.spec.ts). - Document it on a panel page and in the table above, and add a harness scenario when the integration needs one.
Where the module needs to be in the harness, extend harness/start.sh the way WITH_ORM=1 does.