@sigx/lynx-observability 0.5.7 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +107 -107
- package/package.json +3 -3
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025-2026 Andreas Ekdahl
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Andreas Ekdahl
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,107 +1,107 @@
|
|
|
1
|
-
# @sigx/lynx-observability
|
|
2
|
-
|
|
3
|
-
Opt-in **production error capture** and **provider-agnostic log/error sinks** for sigx-lynx. Builds on the logger in [`@sigx/lynx-core`](https://sigx.dev/lynx/modules/core/overview/): uncaught errors are funneled in as `error`-level records, and a "sink" is just a `LogTransport`. No hard dependency on any vendor SDK.
|
|
4
|
-
|
|
5
|
-
> Logging itself ships in the framework (`import { createLogger } from '@sigx/lynx'`). This package adds the *production* pieces — catching crashes and shipping records off-device — and is installed only when you want them.
|
|
6
|
-
|
|
7
|
-
## 📚 Documentation
|
|
8
|
-
|
|
9
|
-
Full guides, API reference and live examples → **[https://sigx.dev/lynx/](https://sigx.dev/lynx/)**
|
|
10
|
-
|
|
11
|
-
## Install
|
|
12
|
-
|
|
13
|
-
```sh
|
|
14
|
-
pnpm add @sigx/lynx-observability
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Quick start — declarative (recommended)
|
|
18
|
-
|
|
19
|
-
Declare it in `signalx.config.ts` and it auto-wires in **release** builds — no code in your app entry:
|
|
20
|
-
|
|
21
|
-
```ts
|
|
22
|
-
// signalx.config.ts
|
|
23
|
-
export default defineLynxConfig({
|
|
24
|
-
name: 'my-app',
|
|
25
|
-
logging: {
|
|
26
|
-
level: 'warn', // logger level (also dev: 'debug' / release: 'warn' default)
|
|
27
|
-
namespaces: { disabled: ['http'] },// silence namespaces at startup
|
|
28
|
-
production: {
|
|
29
|
-
sink: { url: 'https://logs.example.com/ingest', headers: { 'x-api-key': KEY }, sampleRate: 0.25 },
|
|
30
|
-
captureErrors: true, // default
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Just install the package (`pnpm add @sigx/lynx-observability`) — `@sigx/lynx-plugin` prepends the init for you in release builds. (Dev uses the console streamer; observability auto-wiring is release-only.)
|
|
37
|
-
|
|
38
|
-
## Quick start — manual
|
|
39
|
-
|
|
40
|
-
Or wire it yourself, `Sentry.init()`-style (call once in your app entry):
|
|
41
|
-
|
|
42
|
-
```ts
|
|
43
|
-
import { initObservability } from '@sigx/lynx-observability';
|
|
44
|
-
|
|
45
|
-
initObservability({
|
|
46
|
-
level: 'warn', // optional: override the default level
|
|
47
|
-
captureErrors: true, // default — catch uncaught errors / rejections
|
|
48
|
-
sink: { // optional remote sink
|
|
49
|
-
url: 'https://logs.example.com/ingest',
|
|
50
|
-
headers: { 'x-api-key': API_KEY },
|
|
51
|
-
sampleRate: 0.25, // keep 25% of non-error records; errors always kept
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
That's it: uncaught errors now flow to your logs (and the `sigx dev` terminal in development), and records at/above the level are batched and POSTed to your endpoint.
|
|
57
|
-
|
|
58
|
-
## Pieces (compose them yourself)
|
|
59
|
-
|
|
60
|
-
- **`installErrorCapture(opts?)`** — registers Lynx's `lynx.onError` (background thread) plus `globalThis` `error`/`unhandledrejection` handlers, normalizes whatever was thrown into an `Error`, and logs it at `error` level under the `uncaught` namespace. The `Error` rides in the record's `fields`, so transports can treat it as an exception (with a stack). Idempotent; returns an uninstall function.
|
|
61
|
-
- **`createHttpSink(opts)`** — a batching `LogTransport` that POSTs `{ records: [...] }` as JSON to `opts.url`. Options: `batchSize`, `flushIntervalMs`, `sampleRate`, `minLevel`, `headers`, `excludeNamespaces`. `Error` fields are serialized to `{ name, message, stack }`. It excludes the `http` namespace by default (its own POSTs log there) and swallows its own send failures, so it can't feed back into itself. Has a `.flush()` for graceful shutdown.
|
|
62
|
-
- **`toError(value)`** — the normalization helper, exported for reuse.
|
|
63
|
-
|
|
64
|
-
```ts
|
|
65
|
-
import { addTransport } from '@sigx/lynx';
|
|
66
|
-
import { createHttpSink, installErrorCapture } from '@sigx/lynx-observability';
|
|
67
|
-
|
|
68
|
-
addTransport(createHttpSink({ url, minLevel: 'info' }));
|
|
69
|
-
const uninstall = installErrorCapture({ onError: (e) => myAnalytics.track('crash', e.message) });
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Wire format
|
|
73
|
-
|
|
74
|
-
The sink POSTs:
|
|
75
|
-
|
|
76
|
-
```json
|
|
77
|
-
{ "records": [ { "level": "error", "namespace": "uncaught", "msg": "[lynx] …", "fields": [ { "name": "TypeError", "message": "…", "stack": "…" } ], "ts": 1733740000000 } ] }
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## Provider adapters
|
|
81
|
-
|
|
82
|
-
There's no built-in vendor coupling — any provider is a `LogTransport`. Errors arrive as `error`-level records with the `Error` in `fields[0]`, so an adapter can split exceptions from breadcrumbs. Example **Sentry** adapter (Sentry is an optional peer in *your* app, not a dependency of this package):
|
|
83
|
-
|
|
84
|
-
```ts
|
|
85
|
-
import * as Sentry from '@sentry/browser'; // your app's dep
|
|
86
|
-
import { addTransport, installErrorCapture, type LogRecord } from '@sigx/lynx';
|
|
87
|
-
|
|
88
|
-
Sentry.init({ dsn: SENTRY_DSN });
|
|
89
|
-
|
|
90
|
-
addTransport((r: LogRecord) => {
|
|
91
|
-
const err = r.fields.find((f) => f instanceof Error) as Error | undefined;
|
|
92
|
-
if (r.level.name === 'error' && err) {
|
|
93
|
-
Sentry.captureException(err);
|
|
94
|
-
} else {
|
|
95
|
-
Sentry.addBreadcrumb({ category: r.namespace, message: r.msg, level: r.level.name });
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
installErrorCapture();
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
The same shape works for Datadog, a custom backend, etc.
|
|
102
|
-
|
|
103
|
-
## Notes
|
|
104
|
-
|
|
105
|
-
- `lynx.onError` is **background-thread only** upstream; main-thread error capture may need a separate path in the future.
|
|
106
|
-
- For readable stack traces in release builds, upload your source maps to your provider (out of scope here).
|
|
107
|
-
- Declarative `signalx.config.ts` `logging.production` config auto-wires this package in release builds (see Quick start above); `initObservability()` remains for manual/dev setup.
|
|
1
|
+
# @sigx/lynx-observability
|
|
2
|
+
|
|
3
|
+
Opt-in **production error capture** and **provider-agnostic log/error sinks** for sigx-lynx. Builds on the logger in [`@sigx/lynx-core`](https://sigx.dev/lynx/modules/core/overview/): uncaught errors are funneled in as `error`-level records, and a "sink" is just a `LogTransport`. No hard dependency on any vendor SDK.
|
|
4
|
+
|
|
5
|
+
> Logging itself ships in the framework (`import { createLogger } from '@sigx/lynx'`). This package adds the *production* pieces — catching crashes and shipping records off-device — and is installed only when you want them.
|
|
6
|
+
|
|
7
|
+
## 📚 Documentation
|
|
8
|
+
|
|
9
|
+
Full guides, API reference and live examples → **[https://sigx.dev/lynx/](https://sigx.dev/lynx/)**
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
pnpm add @sigx/lynx-observability
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick start — declarative (recommended)
|
|
18
|
+
|
|
19
|
+
Declare it in `signalx.config.ts` and it auto-wires in **release** builds — no code in your app entry:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// signalx.config.ts
|
|
23
|
+
export default defineLynxConfig({
|
|
24
|
+
name: 'my-app',
|
|
25
|
+
logging: {
|
|
26
|
+
level: 'warn', // logger level (also dev: 'debug' / release: 'warn' default)
|
|
27
|
+
namespaces: { disabled: ['http'] },// silence namespaces at startup
|
|
28
|
+
production: {
|
|
29
|
+
sink: { url: 'https://logs.example.com/ingest', headers: { 'x-api-key': KEY }, sampleRate: 0.25 },
|
|
30
|
+
captureErrors: true, // default
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Just install the package (`pnpm add @sigx/lynx-observability`) — `@sigx/lynx-plugin` prepends the init for you in release builds. (Dev uses the console streamer; observability auto-wiring is release-only.)
|
|
37
|
+
|
|
38
|
+
## Quick start — manual
|
|
39
|
+
|
|
40
|
+
Or wire it yourself, `Sentry.init()`-style (call once in your app entry):
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { initObservability } from '@sigx/lynx-observability';
|
|
44
|
+
|
|
45
|
+
initObservability({
|
|
46
|
+
level: 'warn', // optional: override the default level
|
|
47
|
+
captureErrors: true, // default — catch uncaught errors / rejections
|
|
48
|
+
sink: { // optional remote sink
|
|
49
|
+
url: 'https://logs.example.com/ingest',
|
|
50
|
+
headers: { 'x-api-key': API_KEY },
|
|
51
|
+
sampleRate: 0.25, // keep 25% of non-error records; errors always kept
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
That's it: uncaught errors now flow to your logs (and the `sigx dev` terminal in development), and records at/above the level are batched and POSTed to your endpoint.
|
|
57
|
+
|
|
58
|
+
## Pieces (compose them yourself)
|
|
59
|
+
|
|
60
|
+
- **`installErrorCapture(opts?)`** — registers Lynx's `lynx.onError` (background thread) plus `globalThis` `error`/`unhandledrejection` handlers, normalizes whatever was thrown into an `Error`, and logs it at `error` level under the `uncaught` namespace. The `Error` rides in the record's `fields`, so transports can treat it as an exception (with a stack). Idempotent; returns an uninstall function.
|
|
61
|
+
- **`createHttpSink(opts)`** — a batching `LogTransport` that POSTs `{ records: [...] }` as JSON to `opts.url`. Options: `batchSize`, `flushIntervalMs`, `sampleRate`, `minLevel`, `headers`, `excludeNamespaces`. `Error` fields are serialized to `{ name, message, stack }`. It excludes the `http` namespace by default (its own POSTs log there) and swallows its own send failures, so it can't feed back into itself. Has a `.flush()` for graceful shutdown.
|
|
62
|
+
- **`toError(value)`** — the normalization helper, exported for reuse.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { addTransport } from '@sigx/lynx';
|
|
66
|
+
import { createHttpSink, installErrorCapture } from '@sigx/lynx-observability';
|
|
67
|
+
|
|
68
|
+
addTransport(createHttpSink({ url, minLevel: 'info' }));
|
|
69
|
+
const uninstall = installErrorCapture({ onError: (e) => myAnalytics.track('crash', e.message) });
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Wire format
|
|
73
|
+
|
|
74
|
+
The sink POSTs:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{ "records": [ { "level": "error", "namespace": "uncaught", "msg": "[lynx] …", "fields": [ { "name": "TypeError", "message": "…", "stack": "…" } ], "ts": 1733740000000 } ] }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Provider adapters
|
|
81
|
+
|
|
82
|
+
There's no built-in vendor coupling — any provider is a `LogTransport`. Errors arrive as `error`-level records with the `Error` in `fields[0]`, so an adapter can split exceptions from breadcrumbs. Example **Sentry** adapter (Sentry is an optional peer in *your* app, not a dependency of this package):
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import * as Sentry from '@sentry/browser'; // your app's dep
|
|
86
|
+
import { addTransport, installErrorCapture, type LogRecord } from '@sigx/lynx';
|
|
87
|
+
|
|
88
|
+
Sentry.init({ dsn: SENTRY_DSN });
|
|
89
|
+
|
|
90
|
+
addTransport((r: LogRecord) => {
|
|
91
|
+
const err = r.fields.find((f) => f instanceof Error) as Error | undefined;
|
|
92
|
+
if (r.level.name === 'error' && err) {
|
|
93
|
+
Sentry.captureException(err);
|
|
94
|
+
} else {
|
|
95
|
+
Sentry.addBreadcrumb({ category: r.namespace, message: r.msg, level: r.level.name });
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
installErrorCapture();
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The same shape works for Datadog, a custom backend, etc.
|
|
102
|
+
|
|
103
|
+
## Notes
|
|
104
|
+
|
|
105
|
+
- `lynx.onError` is **background-thread only** upstream; main-thread error capture may need a separate path in the future.
|
|
106
|
+
- For readable stack traces in release builds, upload your source maps to your provider (out of scope here).
|
|
107
|
+
- Declarative `signalx.config.ts` `logging.production` config auto-wires this package in release builds (see Quick start above); `initObservability()` remains for manual/dev setup.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sigx/lynx-observability",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Opt-in production error capture + provider-agnostic log/error sinks for sigx-lynx",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"url": "https://github.com/signalxjs/lynx/issues"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@sigx/lynx-core": "^0.
|
|
42
|
-
"@sigx/lynx-http": "^0.
|
|
41
|
+
"@sigx/lynx-core": "^0.6.1",
|
|
42
|
+
"@sigx/lynx-http": "^0.6.1"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@typescript/native-preview": "7.0.0-dev.20260521.1",
|