From 3f898416bde6afdf5cdea1a20c640a48fcd19161 Mon Sep 17 00:00:00 2001 From: Ricardo Devis Agullo Date: Fri, 24 Jul 2026 12:12:07 +0200 Subject: [PATCH] Document local mode correctly and component logging via plugins Clarify that local is oc dev mode (not a storage toggle), and guide operators to log from components with a context-aware plugin instead of enabling console in production. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- website/docs/reference/faq.md | 8 ++ .../docs/registry/registry-configuration.md | 129 ++++++++++++++++-- 2 files changed, 125 insertions(+), 12 deletions(-) diff --git a/website/docs/reference/faq.md b/website/docs/reference/faq.md index f827a4a..9253ecd 100644 --- a/website/docs/reference/faq.md +++ b/website/docs/reference/faq.md @@ -156,6 +156,14 @@ oc preview http://localhost:3030/your-component 3. **CORS issues** - Verify cross-origin settings 4. **SSL/HTTPS** - Ensure proper SSL configuration +### Why don't I see `console.log` from my component outside `oc dev`? + +In local development (`oc dev`), the registry runs with `local: true` and forwards component `console.*` calls to the process console. On a normal (non-local) registry — including staging and production with remote storage — those calls are discarded. + +This is by design. `local` is **not** a "use filesystem storage" flag you can flip in lower environments to get logs back. Setting `local: true` on a deployed registry also disables publishing and changes other production behaviour. + +For intentional logging in any environment, register a logging plugin and call it from `server.js`. See [Logging from components](../registry/registry-configuration#logging-from-components). + ### Template compilation errors **For ES6 templates (default):** diff --git a/website/docs/registry/registry-configuration.md b/website/docs/registry/registry-configuration.md index 693251d..9541fba 100644 --- a/website/docs/registry/registry-configuration.md +++ b/website/docs/registry/registry-configuration.md @@ -129,9 +129,9 @@ For unsuscribing to all [events](#registry-events). | ------------------------- | ----------------- | --------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | discovery | boolean | no | `true` | Enables the HTML discovery page and `/components` endpoint | | discoveryFunc | function | no | - | Function to decide whether discovery should be enabled for the current request. Function signature: `(opts: { host?: string; secure: boolean }) => boolean` | -| local | boolean | no | - | Indicates whether the registry serves components from the local file system (`true`) or from remote storage (`false`) | -| path | string | no | - | Absolute path where local components are stored (used when `local` is `true`) | -| hotReloading | boolean | no | `!!local` | Enables hot-reloading of component code. Always `true` when `local` is `true` | +| local | boolean | no | - | Enables **local development mode** (what `oc dev` sets). Not a storage selector — see [Local development mode](#local-development-mode) | +| path | string | no | - | Absolute path where local components are stored (required when `local` is `true`) | +| hotReloading | boolean | no | `!!local` | Enables hot-reloading of component code. Defaults to `true` when `local` is `true` | | liveReloadPort | number | no | - | TCP port of the LiveReload server used by the preview page | | compileClient | boolean or object | no | `true` | Set options for the oc-client-browser compilation. Set to `false` to disable client compilation, or provide options object for custom compilation settings | @@ -255,6 +255,8 @@ registry.start(); ### Local Development Configuration +Prefer `oc dev` over hand-rolling this. The CLI starts a registry with `local: true` and the right defaults for day-to-day component work. + ```js var oc = require("oc"); @@ -274,6 +276,22 @@ var registry = new oc.Registry(configuration); registry.start(); ``` +#### Local development mode + +`local: true` turns on **local development mode**. It is **not** a toggle between "filesystem storage" and "remote storage" that you would flip in staging or production. + +When `local` is `true`, the registry: + +- Serves components from a local directory (`path`) instead of a storage adapter +- **Disables publishing** — components cannot be published to a local registry +- Enables hot-reloading of component code (unless you override `hotReloading`) +- Forwards component `console.*` calls to the process console (so `console.log` in `server.js` is visible while developing) +- Sets `NODE_ENV` to `development` inside the component sandbox +- Surfaces richer server-side error details (including processed stack frames) in responses and logs +- Skips storage/metadata validation that production registries require + +Do **not** set `local: true` on a deployed registry to get component logs or filesystem-like behaviour. You will lose publishing and change other production semantics. For intentional logging outside `oc dev`, use a [logging plugin](#logging-from-components). + ### Custom Storage Adapter Configuration ```js @@ -462,14 +480,11 @@ module.exports.execute = function (context) { return connection.get(featureName); }; }; - -// Enable context awareness -module.exports.context = true; ``` ### Plugin Registration -This is how to register plugins in a registry: +This is how to register plugins in a registry. Context awareness is enabled with `context: true` on the **registration** object (not on the plugin module): ```js // ./registry/init.js @@ -488,6 +503,7 @@ registry.register({ // Register a context-aware plugin registry.register({ name: "getSecureFeature", + context: true, register: require("./oc-plugins/feature-flags"), options: { connectionString: connectionString, @@ -512,6 +528,78 @@ module.exports.data = function (context, callback) { }; ``` +### Logging from components + +Outside `oc dev`, component `console.log` / `console.error` / etc. are discarded. That is intentional: the registry sandbox does not ship every component's unstructured console output into production process logs. + +`local: true` is not a production logging switch (see [Local development mode](#local-development-mode)). For logging in staging or production, register a plugin and call it from `server.js`. + +A minimal context-aware logger: + +```js +// ./registry/oc-plugins/log.js +var logger; + +module.exports.register = function (options, dependencies, next) { + // options.logger is your real logger (pino, winston, Datadog client, ...) + logger = options.logger; + next(); +}; + +// With context: true on registry.register(...), execute receives component +// context and returns the function exposed as context.plugins.log(...) +module.exports.execute = function (context) { + return function (level, message, meta) { + logger[level]({ + component: context.name, + version: context.version, + message: message, + ...(meta || {}), + }); + }; +}; +``` + +Register it on the registry (note `context: true` on the registration object): + +```js +registry.register({ + name: "log", + context: true, + register: require("./oc-plugins/log"), + options: { + logger: myLogger, // your structured logger + }, +}); +``` + +Declare and use it from the component: + +```js +// package.json (component) +// "oc": { "plugins": ["log"] } + +// server.js +module.exports.data = function (context, callback) { + context.plugins.log("info", "fetching user", { id: context.params.userId }); + + // ... + + callback(null, { + /* view model */ + }); +}; +``` + +Why a plugin instead of turning on `console` in production: + +- **Opt-in** — only components that call the plugin pay the cost +- **Structured** — level, message, and metadata can go to your monitoring stack +- **Scoped** — with `context: true`, every line can include component name and version +- **Controlled** — the registry owns sampling, redaction, and destinations + +`verbosity` only controls the registry's own access/process logging. It does not enable component sandbox `console` output. + ### When to Use Context Awareness Context awareness is useful when you need to: @@ -574,8 +662,16 @@ module.exports.execute = function (context) { } }; }; +``` + +Register with `context: true`: -module.exports.context = true; +```js +registry.register({ + name: "advancedFeatureManager", + context: true, + register: require("./oc-plugins/advanced-feature-manager"), +}); ``` ### Plugin Dependencies @@ -593,7 +689,7 @@ module.exports.register = function (options, dependencies, next) { // This register function is only called after all dependencies are registered client.connect(options.connectionString, function (err, conn) { connection = conn; - dependencies.log("secure logger client initialized"); + dependencies.log.handler("secure logger client initialized"); next(); }); }; @@ -612,8 +708,17 @@ module.exports.execute = function (context) { return connection.log(enrichedMessage); }; }; +``` -module.exports.context = true; +```js +registry.register({ + name: "secureLogger", + context: true, + register: require("./oc-plugins/secure-logger"), + options: { + connectionString: connectionString, + }, +}); ``` ### Plugin Configuration Options @@ -623,11 +728,11 @@ module.exports.context = true; | `name` | string | yes | - | Unique identifier for the plugin | | `register` | object | yes | - | Plugin module with register and execute functions | | `options` | object | no | `{}` | Configuration options passed to the plugin | -| `context` | boolean | no | `false` | Enable component context awareness | +| `context` | boolean | no | `false` | Enable component context awareness on `registry.register(...)` | ### Context Object Structure -When `context: true` is set, the context object passed to the execute function contains: +When `context: true` is set on `registry.register(...)`, the context object passed to the execute function contains: ```js {