This is an automated email from the ASF dual-hosted git repository.

wu-sheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-horizon-ui.git

commit 1fd965986fc82b66a790cdc912a28e7c58c784b2
Author: Wu Sheng <[email protected]>
AuthorDate: Mon May 18 21:07:57 2026 +0800

    logging: treat local `node dist/server.js` as production (quiet); only 
`pnpm dev` is dev
    
    The previous logger default flipped on `NODE_ENV !== 'production'`, so
    `node dist/server.js` without an explicit env var fell into dev mode
    (verbose pretty logs). The published binary is a production target —
    it should be quiet by default and emit JSON for log aggregators.
    
    Inverted: dev mode requires `NODE_ENV=development` explicitly.
    Everything else (the local binary, the Docker image, CI) is production.
    
    - logger.ts: `isDev = NODE_ENV === 'development'`. Dev → debug+pretty,
      prod → error+JSON. Doc-comment spells out where each mode kicks in.
    - apps/bff dev script sets `NODE_ENV=development` explicitly so the
      contributor workflow (`pnpm --filter bff dev`) keeps the verbose +
      per-request access logs that make iteration fast.
    - container-image.md updated to reflect: any non-development entry
      point lands in the production log shape.
    - README Development section rewritten — replaced stale `npm install`
      recipe with the real pnpm-based loop, added the binary + image
      paths, and documented the two log modes + the LOG_LEVEL knob for
      triage.
    
    verified: tests 77/77, lint clean, license-eye clean.
---
 README.md                     | 39 +++++++++++++++++++++++++++++++--------
 apps/bff/package.json         |  2 +-
 apps/bff/src/logger.ts        | 19 ++++++++++++++-----
 docs/setup/container-image.md |  4 ++--
 4 files changed, 48 insertions(+), 16 deletions(-)

diff --git a/README.md b/README.md
index 65fb970..b46184c 100644
--- a/README.md
+++ b/README.md
@@ -88,18 +88,41 @@ Horizon UI is built against the SkyWalking OAP GraphQL 
query-protocol (same sche
 
 ## Development
 
-Requires Node.js 20+.
+Requires Node.js 20+ and pnpm 10+ (pinned via Corepack in `package.json`).
 
 ```bash
-npm install
-npm run dev          # vite dev server (proxies /graphql to 
http://127.0.0.1:12800)
-npm run build        # production build
-npm run type-check
-npm run lint
-npm run test:unit
-npm run license:check
+pnpm install                     # one-time / after lockfile changes; 
auto-builds workspace packages via `prepare`
+
+# Dev loop (hot-reload, verbose pretty logs)
+pnpm --filter bff dev            # BFF on :8081 with NODE_ENV=development → 
debug level + per-request access logs
+pnpm --filter ui dev             # Vite dev server on :9091, proxies /api to 
the BFF
+
+# Static checks / tests
+pnpm -r type-check
+pnpm -r lint                     # read-only; `pnpm -r lint:fix` to mutate
+pnpm -r test:unit
+pnpm license:check               # CI gate via skywalking-eyes
+
+# Self-contained "binary mode" — produces ./dist/ that boots with `node 
dist/server.js`
+pnpm package
+HORIZON_CONFIG=./horizon.yaml HORIZON_STATIC_DIR=./dist/static node 
dist/server.js
+
+# Container — Docker just copies in the pre-built dist (no compile in image)
+docker build -t horizon-ui:local .
+docker run --rm -p 8081:8081 -v "$PWD/horizon.yaml:/app/horizon.yaml:ro" 
horizon-ui:local
 ```
 
+### Logging
+
+The BFF uses [pino](https://github.com/pinojs/pino). Two modes, picked from 
`NODE_ENV`:
+
+| Mode | When | Format | Default level |
+|---|---|---|---|
+| **Dev** | `pnpm --filter bff dev` (sets `NODE_ENV=development`) | Pretty, 
colorized, via `pino-pretty` | `debug` + per-request access logs |
+| **Prod** | Everything else — `node dist/server.js`, Docker container, CI | 
One JSON object per line on stdout | `error` — quiet by default |
+
+Adjust with `LOG_LEVEL`: `info` opens per-request access logs in prod, `debug` 
adds lifecycle chatter, `trace` is everything. Genuine request errors stay 
logged at `error` under any default that includes `error`. See 
[docs/setup/container-image.md → 
Logging](docs/setup/container-image.md#logging) for the three orthogonal 
channels (app logs, audit log, wire-debug log) and example `jq` recipes.
+
 ## License
 
 Apache 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
diff --git a/apps/bff/package.json b/apps/bff/package.json
index 9e50ba6..b7b50d4 100644
--- a/apps/bff/package.json
+++ b/apps/bff/package.json
@@ -8,7 +8,7 @@
     "dist"
   ],
   "scripts": {
-    "dev": "tsx watch src/server.ts",
+    "dev": "NODE_ENV=development tsx watch src/server.ts",
     "build": "esbuild src/server.ts --bundle --platform=node --format=esm 
--target=node20 --outfile=dist/server.js --packages=external",
     "cli:hash": "tsx src/cli/hash.ts",
     "type-check": "tsc --noEmit",
diff --git a/apps/bff/src/logger.ts b/apps/bff/src/logger.ts
index bbeb0db..576d6b9 100644
--- a/apps/bff/src/logger.ts
+++ b/apps/bff/src/logger.ts
@@ -17,14 +17,23 @@
 
 import pino, { type LoggerOptions } from 'pino';
 
-const isDev = process.env.NODE_ENV !== 'production';
+// Production unless explicitly opted into dev. Matters because the
+// "production target" includes both `node dist/server.js` (local
+// binary) and the Docker image — both should be quiet by default and
+// emit machine-readable JSON for log aggregators. Only `pnpm dev` /
+// `tsx watch` flips into dev mode (its `dev` script sets
+// NODE_ENV=development).
+const isDev = process.env.NODE_ENV === 'development';
 
 /**
  * Default log level:
- *   - dev: `debug` (verbose, helpful while iterating)
- *   - prod: `error` (quiet by default — Fastify's per-request `info`
- *     access logs are suppressed; only warnings, errors, and fatals
- *     reach stdout)
+ *   - dev (`NODE_ENV=development`, e.g. `pnpm --filter bff dev`):
+ *     `debug` — verbose lifecycle + per-request access logs, pretty-
+ *     printed via `pino-pretty` for human reading.
+ *   - prod (anything else, incl. local `node dist/server.js` and the
+ *     Docker image): `error` — quiet by default. Fastify's per-request
+ *     `info` access logs are suppressed; only warnings, errors, and
+ *     fatals reach stdout as JSON.
  *
  * Operators turn it up explicitly when triaging: `LOG_LEVEL=info` for
  * access logs, `LOG_LEVEL=debug` for the lifecycle chatter, `trace`
diff --git a/docs/setup/container-image.md b/docs/setup/container-image.md
index 2ce6ccd..3d31312 100644
--- a/docs/setup/container-image.md
+++ b/docs/setup/container-image.md
@@ -224,8 +224,8 @@ The BFF uses [pino](https://github.com/pinojs/pino) and 
writes **structured JSON
 
 | Mode | How to enter | Output |
 |---|---|---|
-| Production | The image sets `NODE_ENV=production`. Local: 
`NODE_ENV=production node dist/server.js`. | One JSON object per line on 
stdout. **Default level `error`** — quiet by default; only warnings, errors, 
and fatals reach stdout. Fields: `level`, `time`, `pid`, `hostname`, plus 
per-event keys (`reqId`, `req`, `res`, `responseTime`, `msg`, …). |
-| Development | The local binary defaults to dev (`NODE_ENV` unset). | 
Pretty-printed, colorized, with timestamps via `pino-pretty`. Default level 
`debug`. Same fields, human-readable. |
+| Production | The image sets `NODE_ENV=production`. Anything that isn't 
explicitly `NODE_ENV=development` is treated as production — including the 
local binary `node dist/server.js`. | One JSON object per line on stdout. 
**Default level `error`** — quiet by default; only warnings, errors, and fatals 
reach stdout. Fields: `level`, `time`, `pid`, `hostname`, plus per-event keys 
(`reqId`, `req`, `res`, `responseTime`, `msg`, …). |
+| Development | `pnpm --filter bff dev` (the `dev` script sets 
`NODE_ENV=development` explicitly). | Pretty-printed, colorized, with 
timestamps via `pino-pretty`. **Default level `debug`** — full lifecycle 
chatter + per-request access logs. Human-readable. |
 
 Adjust the floor with `LOG_LEVEL` when triaging:
 

Reply via email to