feat!: API options object support to control sentry handling; removal of logger.sentry.
This commit is contained in:
@@ -5,41 +5,201 @@ Intentional, namespaced logging for TypeScript browser and Node.js applications.
|
||||
```ts
|
||||
import { createLogger } from "@mifi/logger";
|
||||
|
||||
const logger = createLogger({ environment: "production" });
|
||||
logger.child("WIDGET").debug("Rendered", () => ({ expensive: "only evaluated when shown" }));
|
||||
const logger = createLogger({ environment: "production", namespace: "WIDGET" });
|
||||
logger.child("Button").debug("Rendered", () => ({ expensive: "only evaluated when shown" }));
|
||||
```
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
pnpm add @mifi/logger
|
||||
```
|
||||
|
||||
Requires Node.js `>=24`. Published to the private `@mifi` registry.
|
||||
|
||||
## Quick start
|
||||
|
||||
```ts
|
||||
import { createLogger } from "@mifi/logger";
|
||||
|
||||
const logger = createLogger({
|
||||
environment: "development", // "development" | "staging" | "production"
|
||||
namespace: "API", // optional; string or string[] joined with ":"
|
||||
});
|
||||
|
||||
logger.trace("very detailed");
|
||||
logger.debug("diagnostic", () => ({ snapshot: heavyWork() }));
|
||||
logger.info("ready");
|
||||
logger.warn("slow response", { ms: 1200 });
|
||||
logger.error("request failed", error);
|
||||
logger.assert(userId, "missing user id");
|
||||
|
||||
const auth = logger.child("auth"); // namespace → "API:auth"
|
||||
auth.info("token refreshed");
|
||||
```
|
||||
|
||||
Console utility methods (`group`, `groupCollapsed`, `table`, `time`, `count`, `dir`, …) are available and gated by the same level policy as `info`.
|
||||
|
||||
## Runtime policy
|
||||
|
||||
Development shows every level, staging shows `warn` and `error`, and production shows `error` only. Browser sessions can override the policy with `sessionStorage.showLoggingFor`:
|
||||
Default levels by environment:
|
||||
|
||||
```text
|
||||
debug
|
||||
debug:WIDGET,API
|
||||
| Environment | Default level | Console shows |
|
||||
| ------------- | ------------- | --------------- |
|
||||
| `development` | `trace` | all levels |
|
||||
| `staging` | `warn` | `warn`, `error` |
|
||||
| `production` | `error` | `error` only |
|
||||
|
||||
Levels in order (most → least verbose): `trace` → `debug` → `info` → `warn` → `error` → `silent`.
|
||||
|
||||
### Override precedence
|
||||
|
||||
Highest wins:
|
||||
|
||||
1. Explicit `level` option on `createLogger`
|
||||
2. Browser `sessionStorage.showLoggingFor`
|
||||
3. Env vars `MIFI_LOG_LEVEL` / `MIFI_LOG_NAMESPACES`
|
||||
4. Environment default (table above)
|
||||
|
||||
### Browser session override
|
||||
|
||||
```js
|
||||
sessionStorage.setItem("showLoggingFor", "debug");
|
||||
// or restrict to namespaces (exact or descendants):
|
||||
sessionStorage.setItem("showLoggingFor", "debug:WIDGET,API");
|
||||
```
|
||||
|
||||
Containers can use `MIFI_LOG_LEVEL` and `MIFI_LOG_NAMESPACES`. Explicit `level` options take precedence.
|
||||
`WIDGET` matches `WIDGET` and `WIDGET:Button`.
|
||||
|
||||
### Container / Node env overrides
|
||||
|
||||
See [Environment variables](#environment-variables) and [`env.example`](./env.example).
|
||||
|
||||
```bash
|
||||
MIFI_LOG_LEVEL=debug
|
||||
MIFI_LOG_NAMESPACES=WIDGET,API
|
||||
```
|
||||
|
||||
## Environment variables
|
||||
|
||||
These are read from `process.env` (or from `options.env` when testing/injecting):
|
||||
|
||||
| Variable | Description |
|
||||
| --------------------- | --------------------------------------------------------------------------- |
|
||||
| `MIFI_LOG_LEVEL` | Override level: `trace`, `debug`, `info`, `warn`, `error`, or `silent`. |
|
||||
| `MIFI_LOG_NAMESPACES` | Optional comma-separated namespace filters applied with the level override. |
|
||||
|
||||
When only `MIFI_LOG_LEVEL` is set, all namespaces are enabled at that level. When `MIFI_LOG_NAMESPACES` is also set, only matching namespaces (and their children) emit at that level.
|
||||
|
||||
Copy [`env.example`](./env.example) as a starting point for local or container config.
|
||||
|
||||
## Sentry
|
||||
|
||||
The Sentry adapter has no SDK dependency. Provide the SDK that your application already uses. In a production browser, errors go to Sentry without also appearing in the console. In Node, they go to both Sentry and stderr. Use `logger.sentry` to explicitly capture selected non-error events without changing the default policy or writing them to the console when they are otherwise suppressed.
|
||||
The Sentry adapter has **no SDK dependency**. Provide the SDK your application already uses via `@mifi/logger/sentry`.
|
||||
|
||||
**Development never sends to Sentry.** Staging and production attach the sink when `sentry` is configured.
|
||||
|
||||
Destination policy when `sentry` is configured and `sinks` is not:
|
||||
|
||||
| Runtime + environment | Console | Sentry |
|
||||
| ---------------------- | ------------------------------- | ------------------------------------------- |
|
||||
| Production **browser** | Off | Issues for errors; optional Logs |
|
||||
| Production **Node** | On (stderr for errors) | Issues for errors; optional Logs |
|
||||
| Staging | On (default `warn`+) | Issues for errors; optional Logs |
|
||||
| Development | On | Nothing |
|
||||
|
||||
### Issues vs Logs
|
||||
|
||||
- **Errors** → Sentry Issues (`captureException` / `captureMessage`). Not also written to Logs.
|
||||
- **Warnings and lower** → Sentry Logs (`sentry.logger.*`) only when `{ logs: true }` on the sink (or forced per call).
|
||||
|
||||
Default Sentry Logs thresholds when `logs` is enabled:
|
||||
|
||||
| Environment | Logs threshold |
|
||||
| ----------- | -------------- |
|
||||
| Staging | `info` |
|
||||
| Production | `warn` |
|
||||
|
||||
Override with `logLevel` on `createSentrySink`. Console policy stays independent — production browsers can stay quiet while warnings still appear in Sentry Logs.
|
||||
|
||||
### Per-call options
|
||||
|
||||
`trace` / `debug` / `log` / `info` / `warn` / `error` (and `assert`) accept a trailing options object. Console utilities (`group`, `time`, …) do not.
|
||||
|
||||
```ts
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
import { createLogger } from "@mifi/logger";
|
||||
import { createSentrySink } from "@mifi/logger/sentry";
|
||||
|
||||
const logger = createLogger({ environment: "production", sentry: createSentrySink(Sentry) });
|
||||
const logger = createLogger({
|
||||
environment: "production",
|
||||
namespace: "API",
|
||||
sentry: createSentrySink(Sentry, { logs: true }),
|
||||
});
|
||||
|
||||
logger.sentry.info("Cache warmed", { entries: 42 });
|
||||
logger.error("Request failed", error, { requestId: "req_1" });
|
||||
logger.warn("slow", { ms: 1200 }); // → Sentry Logs in production
|
||||
logger.info("investigating", { orderId }, { sentry: true }); // force Logs
|
||||
logger.error("expected", err, { suppressSentry: true }); // console only (when enabled)
|
||||
```
|
||||
|
||||
| Option | Effect |
|
||||
| ----------------- | ---------------------------------------------------------------------- |
|
||||
| `sentry: true` | Force this event to Sentry Logs (ignores Logs threshold; not for errors) |
|
||||
| `suppressSentry: true` | Skip creating a Sentry Issue for an error |
|
||||
|
||||
A last argument is treated as options only when every key is `sentry` or `suppressSentry`. Prefer the third-argument form when you also pass data.
|
||||
|
||||
Logs payload: string message + flat primitive attributes (including `logger.namespace`). Nested objects are not unfurled.
|
||||
|
||||
## Custom sinks
|
||||
|
||||
Replace the default destinations entirely with `sinks`:
|
||||
|
||||
```ts
|
||||
import { createLogger, createConsoleSink, type LogSink } from "@mifi/logger";
|
||||
|
||||
const analyticsSink: LogSink = {
|
||||
emit(event) {
|
||||
if (event.sendToConsole) analytics.track("log", event);
|
||||
},
|
||||
};
|
||||
|
||||
const logger = createLogger({
|
||||
environment: "production",
|
||||
sinks: [createConsoleSink(), analyticsSink],
|
||||
});
|
||||
```
|
||||
|
||||
When `sinks` is provided, the `sentry` option is not used for default sink selection.
|
||||
|
||||
## API overview
|
||||
|
||||
| Export | From | Purpose |
|
||||
| ---------------------- | --------------------- | ------------------------------------------------ |
|
||||
| `createLogger` | `@mifi/logger` | Build a namespaced, Console-shaped logger |
|
||||
| `createConsoleSink` | `@mifi/logger` | Default styled console destination |
|
||||
| `parseLoggingOverride` | `@mifi/logger` | Parse `debug` / `debug:NS1,NS2` override strings |
|
||||
| `createSentrySink` | `@mifi/logger/sentry` | Adapter for any Sentry-like SDK |
|
||||
|
||||
Types: `Logger`, `LoggerOptions`, `LogLevel`, `LoggerEnvironment`, `LogEvent`, `LogSink`, `LogData`, `LogCallOptions`, and (from `/sentry`) `SentryLike`, `SentryScopeLike`, `SentrySink`, `SentrySinkOptions`.
|
||||
|
||||
Optional destinations live under `src/sinks/` (console, Sentry today; New Relic / Datadog-style adapters can land beside them later). Public import paths stay `@mifi/logger` and `@mifi/logger/sentry`.
|
||||
|
||||
All public APIs include JSDoc with parameter and example documentation in the TypeScript sources.
|
||||
|
||||
## Lazy arguments
|
||||
|
||||
Any function passed **after** the first argument is invoked only if the event is emitted:
|
||||
|
||||
```ts
|
||||
logger.debug("state", () => buildHugeSnapshot()); // skipped when debug is suppressed
|
||||
```
|
||||
|
||||
## Releases
|
||||
|
||||
Woodpecker verifies pull requests and `main`, reports CI to Mattermost, then automatically releases from Conventional Commits merged to `main`. It updates `package.json` and `CHANGELOG.md`, creates a `vX.Y.Z` tag, and publishes to the private `@mifi` registry.
|
||||
|
||||
Use `fix:` for a patch, `feat:` for a minor release, and `!` or a `BREAKING CHANGE:` footer for a major release. Commits such as `docs:`, `test:`, and `chore:` do not release a package. Before enabling the automation, publish and tag the existing `v0.9.1` once as its baseline.
|
||||
Use `fix:` for a patch, `feat:` for a minor release, and `!` or a `BREAKING CHANGE:` footer for a major release. Commits such as `docs:`, `test:`, and `chore:` do not release a package.
|
||||
|
||||
The release workflow uses the existing global `gitea_package_token`, `gitea_registry_username`, `gitea_release_token`, `mattermost_bot_access_token`, `mattermost_tests_channel_id`, `mattermost_pushes_channel_id`, and `mattermost_post_api_url` secrets.
|
||||
|
||||
The repository includes a guarded, one-time manual bootstrap workflow for `v0.9.1`; remove it after that initial package version has been published.
|
||||
|
||||
Reference in New Issue
Block a user