@genesislcap/foundation-utils 15.46.5 → 15.46.6-alpha-606571609.0
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/dist/custom-elements.json +259 -11
- package/dist/dts/env/index.d.ts +1 -0
- package/dist/dts/env/index.d.ts.map +1 -1
- package/dist/dts/env/runtime-config.d.ts +29 -0
- package/dist/dts/env/runtime-config.d.ts.map +1 -0
- package/dist/dts/error-monitoring/error-monitoring.d.ts +147 -0
- package/dist/dts/error-monitoring/error-monitoring.d.ts.map +1 -0
- package/dist/dts/error-monitoring/format-log-args.d.ts +13 -0
- package/dist/dts/error-monitoring/format-log-args.d.ts.map +1 -0
- package/dist/dts/error-monitoring/index.d.ts +3 -0
- package/dist/dts/error-monitoring/index.d.ts.map +1 -0
- package/dist/dts/index.d.ts +1 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/esm/env/index.js +1 -0
- package/dist/esm/env/runtime-config.js +48 -0
- package/dist/esm/error-monitoring/error-monitoring.js +139 -0
- package/dist/esm/error-monitoring/format-log-args.js +52 -0
- package/dist/esm/error-monitoring/index.js +2 -0
- package/dist/esm/index.js +1 -0
- package/dist/foundation-utils.api.json +1432 -36
- package/dist/foundation-utils.d.ts +199 -0
- package/package.json +9 -9
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { addGlobalLogReporter } from '@genesislcap/foundation-logger';
|
|
3
|
+
import { fetchRuntimeConfig } from '../env/runtime-config';
|
|
4
|
+
import { formatLogArgs } from './format-log-args';
|
|
5
|
+
const REPORTED_LOG_TYPES = new Set(['error', 'fatal']);
|
|
6
|
+
/** consola log types mapped to monitoring severities; anything unlisted is `info`. */
|
|
7
|
+
const BREADCRUMB_LEVELS = {
|
|
8
|
+
warn: 'warning',
|
|
9
|
+
debug: 'debug',
|
|
10
|
+
trace: 'debug',
|
|
11
|
+
verbose: 'debug',
|
|
12
|
+
};
|
|
13
|
+
const isPlainObject = (value) => typeof value === 'object' &&
|
|
14
|
+
value !== null &&
|
|
15
|
+
!Array.isArray(value) &&
|
|
16
|
+
!(value instanceof Error) &&
|
|
17
|
+
Object.getPrototypeOf(value) === Object.prototype;
|
|
18
|
+
const nonEmptyString = (value) => typeof value === 'string' && value ? value : undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Creates a global log reporter that sends foundation logger output to a monitoring client.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* `error` and `fatal` logs become events: an exception when an `Error` was logged, otherwise a
|
|
24
|
+
* message built with {@link formatLogArgs}. Each is tagged with the logger name, and plain-object
|
|
25
|
+
* arguments (such as an error boundary's reference ID and component stack) are merged into its
|
|
26
|
+
* extra data alongside the raw arguments. Other logs become breadcrumbs unless `breadcrumbs` is
|
|
27
|
+
* `false`. A failing client never breaks logging.
|
|
28
|
+
*
|
|
29
|
+
* {@link setupErrorMonitoring} registers this for you; use it directly to wire a client by hand.
|
|
30
|
+
*
|
|
31
|
+
* @param client - The monitoring client.
|
|
32
|
+
* @param options - Set `breadcrumbs: false` to skip breadcrumbs.
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
export const createErrorMonitoringReporter = (client, { breadcrumbs = true } = {}) => ({
|
|
36
|
+
log: ({ type, tag, args }) => {
|
|
37
|
+
var _a, _b;
|
|
38
|
+
try {
|
|
39
|
+
if (!REPORTED_LOG_TYPES.has(type)) {
|
|
40
|
+
if (breadcrumbs) {
|
|
41
|
+
(_a = client.addBreadcrumb) === null || _a === void 0 ? void 0 : _a.call(client, {
|
|
42
|
+
category: tag || 'logger',
|
|
43
|
+
level: (_b = BREADCRUMB_LEVELS[type]) !== null && _b !== void 0 ? _b : 'info',
|
|
44
|
+
message: formatLogArgs(args),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const context = {
|
|
50
|
+
level: type === 'fatal' ? 'fatal' : 'error',
|
|
51
|
+
tags: { logger: tag || 'unknown' },
|
|
52
|
+
extra: Object.assign(Object.assign({}, Object.assign({}, ...args.filter(isPlainObject))), { args }),
|
|
53
|
+
};
|
|
54
|
+
const error = args.find((arg) => arg instanceof Error);
|
|
55
|
+
if (error) {
|
|
56
|
+
client.captureException(error, context);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const message = formatLogArgs(args);
|
|
60
|
+
client.captureMessage(tag ? `${tag}: ${message}` : message, context);
|
|
61
|
+
}
|
|
62
|
+
catch (_c) {
|
|
63
|
+
// Monitoring must never break the app's logging.
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
/**
|
|
68
|
+
* True for a console breadcrumb written by a foundation logger.
|
|
69
|
+
*
|
|
70
|
+
* @remarks
|
|
71
|
+
* consola's browser output starts with a `%c` badge, and SDKs that record console calls join the
|
|
72
|
+
* arguments with `String()`, so these breadcrumbs arrive as CSS and `[object Object]`. The
|
|
73
|
+
* reporter from {@link createErrorMonitoringReporter} records the same logs readably.
|
|
74
|
+
* @public
|
|
75
|
+
*/
|
|
76
|
+
export const isFoundationLoggerConsoleBreadcrumb = (breadcrumb) => {
|
|
77
|
+
var _a, _b;
|
|
78
|
+
const first = (_b = (_a = breadcrumb.data) === null || _a === void 0 ? void 0 : _a.arguments) === null || _b === void 0 ? void 0 : _b[0];
|
|
79
|
+
return breadcrumb.category === 'console' && typeof first === 'string' && first.startsWith('%c');
|
|
80
|
+
};
|
|
81
|
+
let removeActiveReporter;
|
|
82
|
+
/**
|
|
83
|
+
* Sets up error monitoring for a Genesis app in one call.
|
|
84
|
+
*
|
|
85
|
+
* @remarks
|
|
86
|
+
* Reads the DSN and environment from per-deployment config (`/env.json` by default) with
|
|
87
|
+
* {@link fetchRuntimeConfig}, so one image can be promoted across environments. Without a DSN it
|
|
88
|
+
* does nothing and resolves `false`, as in local development. Otherwise it:
|
|
89
|
+
*
|
|
90
|
+
* - initialises the client (`client.init`, or `options.init`) with the DSN, environment,
|
|
91
|
+
* `normalizeDepth: 10`, a `beforeBreadcrumb` that drops unreadable foundation logger console
|
|
92
|
+
* breadcrumbs, and any `initOptions`;
|
|
93
|
+
* - registers a global log reporter ({@link createErrorMonitoringReporter}), so errors logged by
|
|
94
|
+
* every foundation logger, including those Genesis packages create at import time, are reported
|
|
95
|
+
* with their structured arguments, and other logs become readable breadcrumbs.
|
|
96
|
+
*
|
|
97
|
+
* Errors caught by the foundation-react-utils `AppErrorBoundary` and `TileErrorBoundary` are logged
|
|
98
|
+
* with their reference ID and component stack, so they are reported too without an `onError`.
|
|
99
|
+
* Pair them with `onCaughtError` on the React root.
|
|
100
|
+
*
|
|
101
|
+
* Calling it again replaces the previous reporter, or removes it if the new call finds no DSN.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* import * as Sentry from '@sentry/react';
|
|
106
|
+
* import { setupErrorMonitoring } from '@genesislcap/foundation-utils';
|
|
107
|
+
*
|
|
108
|
+
* setupErrorMonitoring(Sentry);
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* @param client - The monitoring SDK (for example the Sentry namespace) or an adapter for one.
|
|
112
|
+
* @param options - Config location and keys, and extra init options.
|
|
113
|
+
* @returns Whether monitoring was enabled.
|
|
114
|
+
* @public
|
|
115
|
+
*/
|
|
116
|
+
export function setupErrorMonitoring(client_1) {
|
|
117
|
+
return __awaiter(this, arguments, void 0, function* (client, options = {}) {
|
|
118
|
+
var _a, _b;
|
|
119
|
+
const { configUrl, dsnKey = 'sentryDsn', environmentKey = 'environmentType', defaultEnvironment = 'local', initOptions = {}, init, breadcrumbs = true, } = options;
|
|
120
|
+
const config = yield fetchRuntimeConfig(configUrl);
|
|
121
|
+
removeActiveReporter === null || removeActiveReporter === void 0 ? void 0 : removeActiveReporter();
|
|
122
|
+
removeActiveReporter = undefined;
|
|
123
|
+
const dsn = nonEmptyString(config[dsnKey]);
|
|
124
|
+
if (!dsn) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
const appBeforeBreadcrumb = initOptions.beforeBreadcrumb;
|
|
128
|
+
const beforeBreadcrumb = (breadcrumb) => {
|
|
129
|
+
if (breadcrumbs && isFoundationLoggerConsoleBreadcrumb(breadcrumb)) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
return appBeforeBreadcrumb ? appBeforeBreadcrumb(breadcrumb) : breadcrumb;
|
|
133
|
+
};
|
|
134
|
+
const resolvedInitOptions = Object.assign(Object.assign({ normalizeDepth: 10 }, initOptions), { dsn, environment: (_a = nonEmptyString(config[environmentKey])) !== null && _a !== void 0 ? _a : defaultEnvironment, beforeBreadcrumb });
|
|
135
|
+
yield (init ? init(resolvedInitOptions) : (_b = client.init) === null || _b === void 0 ? void 0 : _b.call(client, resolvedInitOptions));
|
|
136
|
+
removeActiveReporter = addGlobalLogReporter(createErrorMonitoringReporter(client, { breadcrumbs }));
|
|
137
|
+
return true;
|
|
138
|
+
});
|
|
139
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const MAX_MESSAGE_LENGTH = 2000;
|
|
2
|
+
/** `JSON.stringify` replacer that names functions and marks repeated objects instead of throwing. */
|
|
3
|
+
const readableReplacer = () => {
|
|
4
|
+
const seen = new WeakSet();
|
|
5
|
+
return (_key, value) => {
|
|
6
|
+
if (typeof value === 'function') {
|
|
7
|
+
return `[Function ${value.name || 'anonymous'}]`;
|
|
8
|
+
}
|
|
9
|
+
if (typeof value === 'bigint') {
|
|
10
|
+
return `${value}n`;
|
|
11
|
+
}
|
|
12
|
+
if (typeof value === 'object' && value !== null) {
|
|
13
|
+
if (seen.has(value)) {
|
|
14
|
+
return '[Circular]';
|
|
15
|
+
}
|
|
16
|
+
seen.add(value);
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
const stringifyArg = (arg) => {
|
|
22
|
+
var _a;
|
|
23
|
+
if (typeof arg === 'string') {
|
|
24
|
+
return arg;
|
|
25
|
+
}
|
|
26
|
+
if (arg instanceof Error) {
|
|
27
|
+
return arg.message;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
return (_a = JSON.stringify(arg, readableReplacer())) !== null && _a !== void 0 ? _a : String(arg);
|
|
31
|
+
}
|
|
32
|
+
catch (_b) {
|
|
33
|
+
return String(arg);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Builds a readable one-line message from a log call's arguments.
|
|
38
|
+
*
|
|
39
|
+
* @remarks
|
|
40
|
+
* Objects, such as a Genesis NACK, are JSON-encoded rather than becoming `[object Object]`.
|
|
41
|
+
* Circular references are marked, functions and classes are named, errors contribute their message,
|
|
42
|
+
* and the result is capped at 2000 characters.
|
|
43
|
+
*
|
|
44
|
+
* @param args - The arguments passed to the logger.
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
export const formatLogArgs = (args) => args
|
|
48
|
+
.map(stringifyArg)
|
|
49
|
+
.map((part) => part.trim())
|
|
50
|
+
.filter(Boolean)
|
|
51
|
+
.join(' ')
|
|
52
|
+
.slice(0, MAX_MESSAGE_LENGTH);
|
package/dist/esm/index.js
CHANGED