react-native-nitro-logger 0.1.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/LICENSE +20 -0
- package/NitroLogger.podspec +29 -0
- package/README.md +214 -0
- package/android/CMakeLists.txt +24 -0
- package/android/build.gradle +124 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/cpp-adapter.cpp +11 -0
- package/android/src/main/java/com/margelo/nitro/nitrologger/AndroidPlatformIo.kt +100 -0
- package/android/src/main/java/com/margelo/nitro/nitrologger/HybridFileSink.kt +292 -0
- package/android/src/main/java/com/margelo/nitro/nitrologger/HybridNativeConsoleSink.kt +23 -0
- package/android/src/main/java/com/margelo/nitro/nitrologger/LogFileWriter.kt +1328 -0
- package/android/src/main/java/com/margelo/nitro/nitrologger/LogRotationPolicy.kt +186 -0
- package/android/src/main/java/com/margelo/nitro/nitrologger/LogSecureFile.kt +80 -0
- package/android/src/main/java/com/margelo/nitro/nitrologger/LogWriterRegistry.kt +420 -0
- package/android/src/main/java/com/margelo/nitro/nitrologger/NativeConsoleWriter.kt +237 -0
- package/android/src/main/java/com/margelo/nitro/nitrologger/NitroLoggerPackage.kt +22 -0
- package/android/src/main/java/com/margelo/nitro/nitrologger/PlatformIo.kt +165 -0
- package/docs/PARITY.md +330 -0
- package/docs/PRIVACY.md +341 -0
- package/eslint-plugin/README.md +238 -0
- package/eslint-plugin/index.js +62 -0
- package/eslint-plugin/rules/literal-subsystem.js +102 -0
- package/eslint-plugin/rules/no-computed-metadata-key.js +174 -0
- package/eslint-plugin/rules/no-derived-correlation.js +171 -0
- package/eslint-plugin/rules/no-dynamic-message.js +60 -0
- package/eslint-plugin/shared.js +1948 -0
- package/ios/Gzip.swift +203 -0
- package/ios/HybridFileSink.swift +291 -0
- package/ios/HybridNativeConsoleSink.swift +20 -0
- package/ios/LogFileWriter.swift +1280 -0
- package/ios/LogSecureFile.swift +296 -0
- package/ios/LogWriterRegistry.swift +444 -0
- package/ios/NativeConsoleWriter.swift +180 -0
- package/lib/module/Logger.js +381 -0
- package/lib/module/Logger.js.map +1 -0
- package/lib/module/ScopedLogger.js +70 -0
- package/lib/module/ScopedLogger.js.map +1 -0
- package/lib/module/config.js +23 -0
- package/lib/module/config.js.map +1 -0
- package/lib/module/destinations/Batcher.js +647 -0
- package/lib/module/destinations/Batcher.js.map +1 -0
- package/lib/module/destinations/ConsoleDestination.js +51 -0
- package/lib/module/destinations/ConsoleDestination.js.map +1 -0
- package/lib/module/destinations/FileDestination.js +360 -0
- package/lib/module/destinations/FileDestination.js.map +1 -0
- package/lib/module/destinations/NativeConsoleDestination.js +170 -0
- package/lib/module/destinations/NativeConsoleDestination.js.map +1 -0
- package/lib/module/destinations/types.js +4 -0
- package/lib/module/destinations/types.js.map +1 -0
- package/lib/module/formatters/DefaultFormatter.js +136 -0
- package/lib/module/formatters/DefaultFormatter.js.map +1 -0
- package/lib/module/formatters/JsonLinesFormatter.js +162 -0
- package/lib/module/formatters/JsonLinesFormatter.js.map +1 -0
- package/lib/module/formatters/timestamp.js +15 -0
- package/lib/module/formatters/timestamp.js.map +1 -0
- package/lib/module/formatters/types.js +4 -0
- package/lib/module/formatters/types.js.map +1 -0
- package/lib/module/index.js +31 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/integrations/appState.js +81 -0
- package/lib/module/integrations/appState.js.map +1 -0
- package/lib/module/integrations/errorHandler.js +166 -0
- package/lib/module/integrations/errorHandler.js.map +1 -0
- package/lib/module/integrations/sanitizeError.js +238 -0
- package/lib/module/integrations/sanitizeError.js.map +1 -0
- package/lib/module/levels.js +35 -0
- package/lib/module/levels.js.map +1 -0
- package/lib/module/metadata.js +52 -0
- package/lib/module/metadata.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/privacy.js +349 -0
- package/lib/module/privacy.js.map +1 -0
- package/lib/module/specs/FileSink.nitro.js +4 -0
- package/lib/module/specs/FileSink.nitro.js.map +1 -0
- package/lib/module/specs/NativeConsoleSink.nitro.js +4 -0
- package/lib/module/specs/NativeConsoleSink.nitro.js.map +1 -0
- package/lib/module/types.js +4 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/utf8.js +42 -0
- package/lib/module/utf8.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/Logger.d.ts +122 -0
- package/lib/typescript/src/Logger.d.ts.map +1 -0
- package/lib/typescript/src/ScopedLogger.d.ts +36 -0
- package/lib/typescript/src/ScopedLogger.d.ts.map +1 -0
- package/lib/typescript/src/config.d.ts +12 -0
- package/lib/typescript/src/config.d.ts.map +1 -0
- package/lib/typescript/src/destinations/Batcher.d.ts +244 -0
- package/lib/typescript/src/destinations/Batcher.d.ts.map +1 -0
- package/lib/typescript/src/destinations/ConsoleDestination.d.ts +27 -0
- package/lib/typescript/src/destinations/ConsoleDestination.d.ts.map +1 -0
- package/lib/typescript/src/destinations/FileDestination.d.ts +200 -0
- package/lib/typescript/src/destinations/FileDestination.d.ts.map +1 -0
- package/lib/typescript/src/destinations/NativeConsoleDestination.d.ts +86 -0
- package/lib/typescript/src/destinations/NativeConsoleDestination.d.ts.map +1 -0
- package/lib/typescript/src/destinations/types.d.ts +19 -0
- package/lib/typescript/src/destinations/types.d.ts.map +1 -0
- package/lib/typescript/src/formatters/DefaultFormatter.d.ts +22 -0
- package/lib/typescript/src/formatters/DefaultFormatter.d.ts.map +1 -0
- package/lib/typescript/src/formatters/JsonLinesFormatter.d.ts +73 -0
- package/lib/typescript/src/formatters/JsonLinesFormatter.d.ts.map +1 -0
- package/lib/typescript/src/formatters/timestamp.d.ts +6 -0
- package/lib/typescript/src/formatters/timestamp.d.ts.map +1 -0
- package/lib/typescript/src/formatters/types.d.ts +27 -0
- package/lib/typescript/src/formatters/types.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +34 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/integrations/appState.d.ts +33 -0
- package/lib/typescript/src/integrations/appState.d.ts.map +1 -0
- package/lib/typescript/src/integrations/errorHandler.d.ts +55 -0
- package/lib/typescript/src/integrations/errorHandler.d.ts.map +1 -0
- package/lib/typescript/src/integrations/sanitizeError.d.ts +89 -0
- package/lib/typescript/src/integrations/sanitizeError.d.ts.map +1 -0
- package/lib/typescript/src/levels.d.ts +9 -0
- package/lib/typescript/src/levels.d.ts.map +1 -0
- package/lib/typescript/src/metadata.d.ts +23 -0
- package/lib/typescript/src/metadata.d.ts.map +1 -0
- package/lib/typescript/src/privacy.d.ts +103 -0
- package/lib/typescript/src/privacy.d.ts.map +1 -0
- package/lib/typescript/src/specs/FileSink.nitro.d.ts +131 -0
- package/lib/typescript/src/specs/FileSink.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/NativeConsoleSink.nitro.d.ts +21 -0
- package/lib/typescript/src/specs/NativeConsoleSink.nitro.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +37 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/lib/typescript/src/utf8.d.ts +15 -0
- package/lib/typescript/src/utf8.d.ts.map +1 -0
- package/nitro.json +33 -0
- package/nitrogen/generated/android/c++/JAppendResult.hpp +79 -0
- package/nitrogen/generated/android/c++/JClearOutcome.hpp +88 -0
- package/nitrogen/generated/android/c++/JFlushOutcome.hpp +81 -0
- package/nitrogen/generated/android/c++/JHybridFileSinkSpec.cpp +120 -0
- package/nitrogen/generated/android/c++/JHybridFileSinkSpec.hpp +69 -0
- package/nitrogen/generated/android/c++/JHybridNativeConsoleSinkSpec.cpp +71 -0
- package/nitrogen/generated/android/c++/JHybridNativeConsoleSinkSpec.hpp +64 -0
- package/nitrogen/generated/android/c++/JRejectReason.hpp +64 -0
- package/nitrogen/generated/android/c++/JRotationConfig.hpp +77 -0
- package/nitrogen/generated/android/c++/JSinkStatus.hpp +69 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/AppendResult.kt +76 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/ClearOutcome.kt +66 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/FlushOutcome.kt +81 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/HybridFileSinkSpec.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/HybridNativeConsoleSinkSpec.kt +58 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/RejectReason.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/RotationConfig.kt +76 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/SinkStatus.kt +66 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/nitrologgerOnLoad.kt +35 -0
- package/nitrogen/generated/android/nitrologger+autolinking.cmake +83 -0
- package/nitrogen/generated/android/nitrologger+autolinking.gradle +27 -0
- package/nitrogen/generated/android/nitrologgerOnLoad.cpp +70 -0
- package/nitrogen/generated/android/nitrologgerOnLoad.hpp +34 -0
- package/nitrogen/generated/ios/NitroLogger+autolinking.rb +62 -0
- package/nitrogen/generated/ios/NitroLogger-Swift-Cxx-Bridge.cpp +50 -0
- package/nitrogen/generated/ios/NitroLogger-Swift-Cxx-Bridge.hpp +216 -0
- package/nitrogen/generated/ios/NitroLogger-Swift-Cxx-Umbrella.hpp +69 -0
- package/nitrogen/generated/ios/NitroLoggerAutolinking.mm +41 -0
- package/nitrogen/generated/ios/NitroLoggerAutolinking.swift +38 -0
- package/nitrogen/generated/ios/c++/HybridFileSinkSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridFileSinkSpecSwift.hpp +150 -0
- package/nitrogen/generated/ios/c++/HybridNativeConsoleSinkSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNativeConsoleSinkSpecSwift.hpp +87 -0
- package/nitrogen/generated/ios/swift/AppendResult.swift +60 -0
- package/nitrogen/generated/ios/swift/ClearOutcome.swift +50 -0
- package/nitrogen/generated/ios/swift/FlushOutcome.swift +59 -0
- package/nitrogen/generated/ios/swift/HybridFileSinkSpec.swift +61 -0
- package/nitrogen/generated/ios/swift/HybridFileSinkSpec_cxx.swift +227 -0
- package/nitrogen/generated/ios/swift/HybridNativeConsoleSinkSpec.swift +56 -0
- package/nitrogen/generated/ios/swift/HybridNativeConsoleSinkSpec_cxx.swift +148 -0
- package/nitrogen/generated/ios/swift/RejectReason.swift +48 -0
- package/nitrogen/generated/ios/swift/RotationConfig.swift +93 -0
- package/nitrogen/generated/ios/swift/SinkStatus.swift +44 -0
- package/nitrogen/generated/shared/c++/AppendResult.hpp +105 -0
- package/nitrogen/generated/shared/c++/ClearOutcome.hpp +96 -0
- package/nitrogen/generated/shared/c++/FlushOutcome.hpp +107 -0
- package/nitrogen/generated/shared/c++/HybridFileSinkSpec.cpp +28 -0
- package/nitrogen/generated/shared/c++/HybridFileSinkSpec.hpp +84 -0
- package/nitrogen/generated/shared/c++/HybridNativeConsoleSinkSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridNativeConsoleSinkSpec.hpp +64 -0
- package/nitrogen/generated/shared/c++/RejectReason.hpp +84 -0
- package/nitrogen/generated/shared/c++/RotationConfig.hpp +103 -0
- package/nitrogen/generated/shared/c++/SinkStatus.hpp +95 -0
- package/package.json +151 -0
- package/src/Logger.ts +417 -0
- package/src/ScopedLogger.ts +94 -0
- package/src/config.ts +25 -0
- package/src/destinations/Batcher.ts +805 -0
- package/src/destinations/ConsoleDestination.ts +60 -0
- package/src/destinations/FileDestination.ts +473 -0
- package/src/destinations/NativeConsoleDestination.ts +220 -0
- package/src/destinations/types.ts +19 -0
- package/src/formatters/DefaultFormatter.ts +150 -0
- package/src/formatters/JsonLinesFormatter.ts +195 -0
- package/src/formatters/timestamp.ts +12 -0
- package/src/formatters/types.ts +29 -0
- package/src/index.tsx +106 -0
- package/src/integrations/appState.ts +111 -0
- package/src/integrations/errorHandler.ts +223 -0
- package/src/integrations/sanitizeError.ts +287 -0
- package/src/levels.ts +35 -0
- package/src/metadata.ts +52 -0
- package/src/privacy.ts +389 -0
- package/src/specs/FileSink.nitro.ts +144 -0
- package/src/specs/NativeConsoleSink.nitro.ts +21 -0
- package/src/types.ts +45 -0
- package/src/utf8.ts +39 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { LEVEL_TAG } from "../levels.js";
|
|
4
|
+
import { formatTime } from "./timestamp.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* SwiftLogger's default layout minus the `File.swift:42` column (no call-site
|
|
8
|
+
* capture in JS):
|
|
9
|
+
*
|
|
10
|
+
* LEVEL | HH:mm:ss.SSS | [correlation] [subsystem] message {key=value}
|
|
11
|
+
*
|
|
12
|
+
* Metadata renders as `key=value` pairs sorted by key.
|
|
13
|
+
*
|
|
14
|
+
* A multi-line message keeps its lines, indented under the message column:
|
|
15
|
+
*
|
|
16
|
+
* ERROR | 12:15:30.842 | Unhandled TypeError
|
|
17
|
+
* | | at foo (bundle.js:1:2)
|
|
18
|
+
*
|
|
19
|
+
* See {@link CONTINUATION} for why that indent is load-bearing rather than
|
|
20
|
+
* decorative.
|
|
21
|
+
*/
|
|
22
|
+
export class DefaultFormatter {
|
|
23
|
+
format(entry) {
|
|
24
|
+
let tags = '';
|
|
25
|
+
if (entry.correlation !== undefined) {
|
|
26
|
+
tags += `[${escapeControls(entry.correlation)}] `;
|
|
27
|
+
}
|
|
28
|
+
if (entry.subsystem !== undefined) {
|
|
29
|
+
tags += `[${escapeControls(entry.subsystem)}] `;
|
|
30
|
+
}
|
|
31
|
+
let body = `${tags}${formatMessage(entry.message)}`;
|
|
32
|
+
if (entry.metadata) {
|
|
33
|
+
const metadata = entry.metadata;
|
|
34
|
+
const keys = Object.keys(metadata).sort();
|
|
35
|
+
if (keys.length > 0) {
|
|
36
|
+
const pairs = keys.map(k => `${escapeControls(k)}=${escapeControls(String(metadata[k]))}`).join(', ');
|
|
37
|
+
body += ` {${pairs}}`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return `${LEVEL_TAG[entry.level]} | ${formatTime(entry.timestamp)} | ${body}`;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Blanks the tag and timestamp columns, so a continuation line lines up under
|
|
46
|
+
* the message and cannot be read as a record of its own.
|
|
47
|
+
*
|
|
48
|
+
* ERROR | 12:15:30.842 | Unhandled TypeError
|
|
49
|
+
* | | at foo (bundle.js:1:2)
|
|
50
|
+
*
|
|
51
|
+
* Five spaces for the level tag, twelve for `HH:mm:ss.SSS`, and the two
|
|
52
|
+
* separators. A real record always carries a known tag and a timestamp made
|
|
53
|
+
* of digits, so a blank in either column cannot be mistaken for one.
|
|
54
|
+
*/
|
|
55
|
+
const CONTINUATION = `${' '.repeat(5)} | ${' '.repeat(12)} | `;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Renders the message, keeping its lines but never letting one start a record.
|
|
59
|
+
*
|
|
60
|
+
* SwiftLogger leaves `message` completely alone, and this package did too
|
|
61
|
+
* until review pointed out that matching the reference is not the same as
|
|
62
|
+
* being safe. The forgery is the one escaping the structured fields prevents:
|
|
63
|
+
* an error message or an interpolated string carrying
|
|
64
|
+
* `"\nERROR | 00:00:00.000 | patient discharged"` writes a line a reader
|
|
65
|
+
* cannot tell from a real one. Reachability is not theoretical —
|
|
66
|
+
* `no-dynamic-message` is what normally keeps arbitrary text out of this
|
|
67
|
+
* field, and it cannot see a logger wired through a function call.
|
|
68
|
+
*
|
|
69
|
+
* Escaping newlines outright would fix it and ruin the crash handler, which
|
|
70
|
+
* logs stack traces through this field on purpose. Indenting continuation
|
|
71
|
+
* lines keeps them readable and still leaves nothing that parses as a header.
|
|
72
|
+
*
|
|
73
|
+
* This is a deliberate parity difference; docs/PARITY.md records it.
|
|
74
|
+
*/
|
|
75
|
+
function formatMessage(message) {
|
|
76
|
+
// Four things besides \n break a line. A bare \r does, and can also drag
|
|
77
|
+
// the cursor back over what was already printed. U+0085 (NEL) does for any
|
|
78
|
+
// Unicode-aware reader. U+2028 and U+2029 do for anything treating this as
|
|
79
|
+
// JavaScript-flavoured text.
|
|
80
|
+
return message.split(/\r\n|[\n\r\u0085\u2028\u2029]/).map(escapeControls).join(`\n${CONTINUATION}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Renders C0, DEL, C1, and the Unicode line/paragraph separators as escapes.
|
|
85
|
+
*
|
|
86
|
+
* C1 (U+0080–U+009F) matters as much as C0 here and is easy to forget:
|
|
87
|
+
* U+009B is a single-character CSI, so a terminal will happily read what
|
|
88
|
+
* follows it as a cursor-movement or erase sequence, and U+0085 is NEL,
|
|
89
|
+
* which Unicode-aware readers treat as a line break.
|
|
90
|
+
*
|
|
91
|
+
* U+2028 and U+2029 are here for exactly the reason U+0085 is. They are not
|
|
92
|
+
* control characters and a plain `\n`-splitting reader ignores them, but a
|
|
93
|
+
* JavaScript one does not: `^` and `$` under the `m` flag treat both as line
|
|
94
|
+
* terminators, so a log viewer written in JS — the likely kind for this
|
|
95
|
+
* package — sees a line break where a terminal sees none. That asymmetry is
|
|
96
|
+
* worse than either alone, because the forged line is invisible in the tool
|
|
97
|
+
* someone checks the raw file with.
|
|
98
|
+
*
|
|
99
|
+
* This layout is one entry per line, so a newline inside a *structured* field
|
|
100
|
+
* lets whoever supplied that field forge whole log entries. A correlation ID,
|
|
101
|
+
* a subsystem, or a metadata key or value can all arrive from a request
|
|
102
|
+
* header, a username, or a URL; without this, `"a\nERROR | 00:00:00.000 | "`
|
|
103
|
+
* writes a convincing fake line into the log, and the reader has no way to
|
|
104
|
+
* tell it from a real one.
|
|
105
|
+
*
|
|
106
|
+
* The message takes a different route — see {@link formatMessage} — because
|
|
107
|
+
* it has to stay multi-line. Everything else is escaped outright.
|
|
108
|
+
*
|
|
109
|
+
* Clean fields — essentially all of them — are scanned once and returned
|
|
110
|
+
* whole, so this costs nothing in the normal case.
|
|
111
|
+
*/
|
|
112
|
+
function escapeControls(field) {
|
|
113
|
+
// eslint-disable-next-line no-control-regex
|
|
114
|
+
if (!/[\u0000-\u001F\u007F-\u009F\u2028\u2029]/.test(field)) return field;
|
|
115
|
+
let out = '';
|
|
116
|
+
for (const character of field) {
|
|
117
|
+
switch (character) {
|
|
118
|
+
case '\n':
|
|
119
|
+
out += '\\n';
|
|
120
|
+
break;
|
|
121
|
+
case '\r':
|
|
122
|
+
out += '\\r';
|
|
123
|
+
break;
|
|
124
|
+
case '\t':
|
|
125
|
+
out += '\\t';
|
|
126
|
+
break;
|
|
127
|
+
default:
|
|
128
|
+
{
|
|
129
|
+
const code = character.codePointAt(0);
|
|
130
|
+
out += code < 0x20 || code >= 0x7f && code <= 0x9f || code === 0x2028 || code === 0x2029 ? `\\u{${code.toString(16).toUpperCase()}}` : character;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return out;
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=DefaultFormatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["LEVEL_TAG","formatTime","DefaultFormatter","format","entry","tags","correlation","undefined","escapeControls","subsystem","body","formatMessage","message","metadata","keys","Object","sort","length","pairs","map","k","String","join","level","timestamp","CONTINUATION","repeat","split","field","test","out","character","code","codePointAt","toString","toUpperCase"],"sourceRoot":"../../../src","sources":["formatters/DefaultFormatter.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { LEVEL_NAME } from "../levels.js";
|
|
4
|
+
import { utf8Length } from "../utf8.js";
|
|
5
|
+
export { utf8Length };
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* How the `timestamp` field renders.
|
|
9
|
+
*
|
|
10
|
+
* `iso8601` is UTC with milliseconds — `2026-07-27T12:15:30.842Z` — and is
|
|
11
|
+
* what the SwiftLogger goldens are written against. `epochSeconds` emits a
|
|
12
|
+
* JSON number of seconds, for aggregators that would only parse the string
|
|
13
|
+
* back again.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Instants JavaScript can represent as a Date but not as ISO 8601. */
|
|
17
|
+
const MAX_ISO_MS = 8.64e15;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* One JSON object per line, matching SwiftLogger's `JSONLogFormatter`.
|
|
21
|
+
*
|
|
22
|
+
* Keys come out in a fixed order — `timestamp`, `level`, `message`, then the
|
|
23
|
+
* optional `correlation`, `subsystem`, and `metadata` — so that output diffs
|
|
24
|
+
* cleanly and goldens are stable. Absent optionals are omitted rather than
|
|
25
|
+
* written as null, and metadata values keep their JSON type.
|
|
26
|
+
*
|
|
27
|
+
* Metadata keys are sorted, which is also why the object is assembled by hand
|
|
28
|
+
* rather than handed to `JSON.stringify`. JavaScript orders integer-like
|
|
29
|
+
* string keys before all others, so `JSON.stringify({ b: 1, '2': 2 })` puts
|
|
30
|
+
* `2` first no matter what order the keys went in. A metadata key is whatever
|
|
31
|
+
* the caller wrote, `'2'` included, and the Swift side sorts every key the
|
|
32
|
+
* same way.
|
|
33
|
+
*
|
|
34
|
+
* See `docs/PARITY.md` for the field-by-field comparison, including the three
|
|
35
|
+
* fields this formatter deliberately does not emit.
|
|
36
|
+
*/
|
|
37
|
+
export class JsonLinesFormatter {
|
|
38
|
+
/**
|
|
39
|
+
* Every control character is escaped, so a record cannot contain a raw
|
|
40
|
+
* newline and native crash-tail trimming can find record boundaries.
|
|
41
|
+
*/
|
|
42
|
+
framing = 'line';
|
|
43
|
+
constructor(options = {}) {
|
|
44
|
+
this.timestampStyle = options.timestampStyle ?? 'iso8601';
|
|
45
|
+
}
|
|
46
|
+
format(entry) {
|
|
47
|
+
return this.render(entry, entry.message, entry.metadata, false);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Render within a byte budget, shedding content in a fixed order rather
|
|
52
|
+
* than slicing the finished string.
|
|
53
|
+
*
|
|
54
|
+
* Cutting a JSON record to length produces something no parser will accept,
|
|
55
|
+
* and a log line that cannot be parsed is worth less than one that is
|
|
56
|
+
* honestly incomplete. So: drop metadata from the end of sorted key order,
|
|
57
|
+
* then shorten the message, and mark the result `"truncated":true` either
|
|
58
|
+
* way. A reader can tell the difference between a short message and a
|
|
59
|
+
* shortened one.
|
|
60
|
+
*
|
|
61
|
+
* The budget counts UTF-8 bytes, because that is what the sink reserves.
|
|
62
|
+
* An unpaired surrogate never distorts the count here: `JSON.stringify` has
|
|
63
|
+
* already turned it into a six-character `\udXXX` escape by the time
|
|
64
|
+
* anything is measured.
|
|
65
|
+
*
|
|
66
|
+
* When even an empty message will not fit, the result comes back OVER
|
|
67
|
+
* budget: it is the smallest record that still identifies the entry, which
|
|
68
|
+
* is not quite the same as the smallest record possible. `correlation` and
|
|
69
|
+
* `subsystem` survive, because an entry no one can place is worth less than
|
|
70
|
+
* a short one — dropping them would save bytes and leave a line that says
|
|
71
|
+
* nothing about where it came from. Callers deciding whether an entry is
|
|
72
|
+
* renderable at all must therefore measure the result rather than assume it
|
|
73
|
+
* fits.
|
|
74
|
+
*/
|
|
75
|
+
formatWithin(entry, maxBytes) {
|
|
76
|
+
const full = this.format(entry);
|
|
77
|
+
if (utf8Length(full) <= maxBytes) return full;
|
|
78
|
+
|
|
79
|
+
// Metadata first: a dropped field costs the reader one fact, whereas a
|
|
80
|
+
// shortened message can cost them the sentence that explains the others.
|
|
81
|
+
const keys = entry.metadata ? Object.keys(entry.metadata).sort() : [];
|
|
82
|
+
for (let keep = keys.length - 1; keep >= 0; keep -= 1) {
|
|
83
|
+
const subset = {};
|
|
84
|
+
for (const key of keys.slice(0, keep)) {
|
|
85
|
+
subset[key] = entry.metadata[key];
|
|
86
|
+
}
|
|
87
|
+
const candidate = this.render(entry, entry.message, keep === 0 ? undefined : subset, true);
|
|
88
|
+
if (utf8Length(candidate) <= maxBytes) return candidate;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Then the message, by code points so a surrogate pair is never split
|
|
92
|
+
// into a lone half. Escaping means a code point can cost anywhere from
|
|
93
|
+
// one to twelve bytes, so the fit is found by measuring whole rendered
|
|
94
|
+
// records rather than by arithmetic on the message alone.
|
|
95
|
+
const points = Array.from(entry.message);
|
|
96
|
+
let low = 0;
|
|
97
|
+
let high = points.length;
|
|
98
|
+
while (low < high) {
|
|
99
|
+
const mid = Math.ceil((low + high) / 2);
|
|
100
|
+
const candidate = this.render(entry, points.slice(0, mid).join(''), undefined, true);
|
|
101
|
+
if (utf8Length(candidate) <= maxBytes) low = mid;else high = mid - 1;
|
|
102
|
+
}
|
|
103
|
+
return this.render(entry, points.slice(0, low).join(''), undefined, true);
|
|
104
|
+
}
|
|
105
|
+
render(entry, message, metadata, truncated) {
|
|
106
|
+
let json = '{"timestamp":';
|
|
107
|
+
json += this.renderTimestamp(entry.timestamp);
|
|
108
|
+
json += ',"level":' + JSON.stringify(LEVEL_NAME[entry.level]);
|
|
109
|
+
json += ',"message":' + JSON.stringify(message);
|
|
110
|
+
if (entry.correlation !== undefined) {
|
|
111
|
+
json += ',"correlation":' + JSON.stringify(entry.correlation);
|
|
112
|
+
}
|
|
113
|
+
if (entry.subsystem !== undefined) {
|
|
114
|
+
json += ',"subsystem":' + JSON.stringify(entry.subsystem);
|
|
115
|
+
}
|
|
116
|
+
if (metadata) {
|
|
117
|
+
const keys = Object.keys(metadata).sort();
|
|
118
|
+
if (keys.length > 0) {
|
|
119
|
+
json += ',"metadata":{';
|
|
120
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
121
|
+
if (i > 0) json += ',';
|
|
122
|
+
json += JSON.stringify(keys[i]) + ':' + renderValue(metadata[keys[i]]);
|
|
123
|
+
}
|
|
124
|
+
json += '}';
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (truncated) json += ',"truncated":true';
|
|
128
|
+
return json + '}';
|
|
129
|
+
}
|
|
130
|
+
renderTimestamp(epochMs) {
|
|
131
|
+
if (this.timestampStyle === 'epochSeconds') {
|
|
132
|
+
return Number.isFinite(epochMs) ? String(epochMs / 1000) : '0';
|
|
133
|
+
}
|
|
134
|
+
// `toISOString` throws past the representable range, and a formatter that
|
|
135
|
+
// throws takes down the log call that was trying to report a problem.
|
|
136
|
+
if (!Number.isFinite(epochMs) || Math.abs(epochMs) > MAX_ISO_MS) {
|
|
137
|
+
return '"1970-01-01T00:00:00.000Z"';
|
|
138
|
+
}
|
|
139
|
+
return JSON.stringify(new Date(epochMs).toISOString());
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* A metadata value as JSON, keeping its type.
|
|
145
|
+
*
|
|
146
|
+
* Non-finite numbers become quoted strings because JSON has no literal for
|
|
147
|
+
* them, matching what the Swift formatter does. Redaction rejects them long
|
|
148
|
+
* before this point, so the branch exists to keep a hand-built entry from
|
|
149
|
+
* producing `NaN` in the middle of a record rather than because it is
|
|
150
|
+
* reachable through the public API.
|
|
151
|
+
*/
|
|
152
|
+
function renderValue(value) {
|
|
153
|
+
switch (typeof value) {
|
|
154
|
+
case 'string':
|
|
155
|
+
return JSON.stringify(value);
|
|
156
|
+
case 'boolean':
|
|
157
|
+
return value ? 'true' : 'false';
|
|
158
|
+
default:
|
|
159
|
+
return Number.isFinite(value) ? String(value) : JSON.stringify(String(value));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=JsonLinesFormatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["LEVEL_NAME","utf8Length","MAX_ISO_MS","JsonLinesFormatter","framing","constructor","options","timestampStyle","format","entry","render","message","metadata","formatWithin","maxBytes","full","keys","Object","sort","keep","length","subset","key","slice","candidate","undefined","points","Array","from","low","high","mid","Math","ceil","join","truncated","json","renderTimestamp","timestamp","JSON","stringify","level","correlation","subsystem","i","renderValue","epochMs","Number","isFinite","String","abs","Date","toISOString","value"],"sourceRoot":"../../../src","sources":["formatters/JsonLinesFormatter.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/** Local-time `HH:mm:ss.SSS`, matching SwiftLogger's console timestamp.
|
|
4
|
+
* Takes epoch milliseconds (see `LogEntry.timestamp`); plain Date getters +
|
|
5
|
+
* zero-pad — none of the Swift version's caching is needed, these are cheap
|
|
6
|
+
* in JS. */
|
|
7
|
+
export function formatTime(epochMs) {
|
|
8
|
+
const date = new Date(epochMs);
|
|
9
|
+
const hh = String(date.getHours()).padStart(2, '0');
|
|
10
|
+
const mm = String(date.getMinutes()).padStart(2, '0');
|
|
11
|
+
const ss = String(date.getSeconds()).padStart(2, '0');
|
|
12
|
+
const ms = String(date.getMilliseconds()).padStart(3, '0');
|
|
13
|
+
return `${hh}:${mm}:${ss}.${ms}`;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=timestamp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["formatTime","epochMs","date","Date","hh","String","getHours","padStart","mm","getMinutes","ss","getSeconds","ms","getMilliseconds"],"sourceRoot":"../../../src","sources":["formatters/timestamp.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA,OAAO,SAASA,UAAUA,CAACC,OAAe,EAAU;EAClD,MAAMC,IAAI,GAAG,IAAIC,IAAI,CAACF,OAAO,CAAC;EAC9B,MAAMG,EAAE,GAAGC,MAAM,CAACH,IAAI,CAACI,QAAQ,CAAC,CAAC,CAAC,CAACC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC;EACnD,MAAMC,EAAE,GAAGH,MAAM,CAACH,IAAI,CAACO,UAAU,CAAC,CAAC,CAAC,CAACF,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC;EACrD,MAAMG,EAAE,GAAGL,MAAM,CAACH,IAAI,CAACS,UAAU,CAAC,CAAC,CAAC,CAACJ,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC;EACrD,MAAMK,EAAE,GAAGP,MAAM,CAACH,IAAI,CAACW,eAAe,CAAC,CAAC,CAAC,CAACN,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC;EAC1D,OAAO,GAAGH,EAAE,IAAII,EAAE,IAAIE,EAAE,IAAIE,EAAE,EAAE;AAClC","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../../src","sources":["formatters/types.ts"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { NitroModules } from 'react-native-nitro-modules';
|
|
4
|
+
// ── Public API ──────────────────────────────────────────────────────────────
|
|
5
|
+
export { Log, Logger } from "./Logger.js";
|
|
6
|
+
export { ScopedLogger } from "./ScopedLogger.js";
|
|
7
|
+
export { pub, priv } from "./privacy.js";
|
|
8
|
+
export { METADATA_KEY_PATTERN_SOURCE, DROPPED_COUNT_KEY, MAX_CATALOG_SIZE, UNREADABLE_VALUE } from "./privacy.js";
|
|
9
|
+
export { ConsoleDestination } from "./destinations/ConsoleDestination.js";
|
|
10
|
+
export { FileDestination } from "./destinations/FileDestination.js";
|
|
11
|
+
export { NativeConsoleDestination } from "./destinations/NativeConsoleDestination.js";
|
|
12
|
+
export { installErrorHandler } from "./integrations/errorHandler.js";
|
|
13
|
+
export { ERROR_METADATA_KEYS, UNCAUGHT_ERROR_MESSAGE } from "./integrations/errorHandler.js";
|
|
14
|
+
export { flushOnBackground } from "./integrations/appState.js";
|
|
15
|
+
export { sanitizeError, DEFAULT_BUNDLE_NAMES, DEFAULT_MAX_FRAMES, REDACTED_FRAME, REDACTED_MESSAGE, UNKNOWN_ERROR_NAME, NON_ERROR_THROWN } from "./integrations/sanitizeError.js";
|
|
16
|
+
export { Batcher } from "./destinations/Batcher.js";
|
|
17
|
+
export { utf8Length } from "./utf8.js";
|
|
18
|
+
export { DefaultFormatter } from "./formatters/DefaultFormatter.js";
|
|
19
|
+
export { JsonLinesFormatter } from "./formatters/JsonLinesFormatter.js";
|
|
20
|
+
|
|
21
|
+
// ── Spike-era raw sink access ───────────────────────────────────────────────
|
|
22
|
+
// Used by the example app's M0 harness; becomes internal once the
|
|
23
|
+
// FileDestination (M4/M5) and NativeConsoleDestination (M6) wrap these.
|
|
24
|
+
|
|
25
|
+
export function createFileSink() {
|
|
26
|
+
return NitroModules.createHybridObject('FileSink');
|
|
27
|
+
}
|
|
28
|
+
export function createNativeConsoleSink() {
|
|
29
|
+
return NitroModules.createHybridObject('NativeConsoleSink');
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["NitroModules","Log","Logger","ScopedLogger","pub","priv","METADATA_KEY_PATTERN_SOURCE","DROPPED_COUNT_KEY","MAX_CATALOG_SIZE","UNREADABLE_VALUE","ConsoleDestination","FileDestination","NativeConsoleDestination","installErrorHandler","ERROR_METADATA_KEYS","UNCAUGHT_ERROR_MESSAGE","flushOnBackground","sanitizeError","DEFAULT_BUNDLE_NAMES","DEFAULT_MAX_FRAMES","REDACTED_FRAME","REDACTED_MESSAGE","UNKNOWN_ERROR_NAME","NON_ERROR_THROWN","Batcher","utf8Length","DefaultFormatter","JsonLinesFormatter","createFileSink","createHybridObject","createNativeConsoleSink"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,4BAA4B;AAIzD;AACA,SAASC,GAAG,EAAEC,MAAM,QAAQ,aAAU;AAEtC,SAASC,YAAY,QAAQ,mBAAgB;AAU7C,SAASC,GAAG,EAAEC,IAAI,QAAQ,cAAW;AACrC,SACEC,2BAA2B,EAC3BC,iBAAiB,EACjBC,gBAAgB,EAChBC,gBAAgB,QACX,cAAW;AAGlB,SAASC,kBAAkB,QAAQ,sCAAmC;AACtE,SAASC,eAAe,QAAQ,mCAAgC;AAMhE,SAASC,wBAAwB,QAAQ,4CAAyC;AAKlF,SAASC,mBAAmB,QAAQ,gCAA6B;AACjE,SACEC,mBAAmB,EACnBC,sBAAsB,QACjB,gCAA6B;AAMpC,SAASC,iBAAiB,QAAQ,4BAAyB;AAK3D,SACEC,aAAa,EACbC,oBAAoB,EACpBC,kBAAkB,EAClBC,cAAc,EACdC,gBAAgB,EAChBC,kBAAkB,EAClBC,gBAAgB,QACX,iCAA8B;AAKrC,SAASC,OAAO,QAAQ,2BAAwB;AAQhD,SAASC,UAAU,QAAQ,WAAQ;AAEnC,SAASC,gBAAgB,QAAQ,kCAA+B;AAChE,SAASC,kBAAkB,QAAQ,oCAAiC;;AAMpE;AACA;AACA;;AAYA,OAAO,SAASC,cAAcA,CAAA,EAAa;EACzC,OAAO5B,YAAY,CAAC6B,kBAAkB,CAAW,UAAU,CAAC;AAC9D;AAEA,OAAO,SAASC,uBAAuBA,CAAA,EAAsB;EAC3D,OAAO9B,YAAY,CAAC6B,kBAAkB,CACpC,mBACF,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { Log } from "../Logger.js";
|
|
4
|
+
|
|
5
|
+
/** The part of RN's `AppState` this uses. Injected in tests. */
|
|
6
|
+
|
|
7
|
+
const DEFAULT_DEADLINE_MS = 2000;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* States that mean "the JS thread is about to stop being scheduled".
|
|
11
|
+
*
|
|
12
|
+
* Both, not just `background`: iOS passes through `inactive` on the way there,
|
|
13
|
+
* and on some transitions — a phone call, the app switcher — that is as far as
|
|
14
|
+
* it gets. Flushing twice costs nothing, because a flush with nothing pending
|
|
15
|
+
* is a length check on an empty buffer in every destination this library ships.
|
|
16
|
+
*/
|
|
17
|
+
const LEAVING_FOREGROUND = new Set(['inactive', 'background']);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Flushes every destination when the app leaves the foreground.
|
|
21
|
+
*
|
|
22
|
+
* Returns an idempotent uninstall handle. Removing the listener matters more
|
|
23
|
+
* than it looks: `AppState` outlives any component, so a subscription left
|
|
24
|
+
* behind keeps a disposed logger reachable and flushes it on every transition
|
|
25
|
+
* for the rest of the process.
|
|
26
|
+
*/
|
|
27
|
+
export function flushOnBackground(options) {
|
|
28
|
+
const appState = options?.appState ?? resolveAppState();
|
|
29
|
+
if (!appState) return () => {};
|
|
30
|
+
const logger = options?.logger ?? Log;
|
|
31
|
+
const deadlineMs = budget(options?.deadlineMs);
|
|
32
|
+
let subscription;
|
|
33
|
+
try {
|
|
34
|
+
subscription = appState.addEventListener('change', state => {
|
|
35
|
+
if (!LEAVING_FOREGROUND.has(state)) return;
|
|
36
|
+
try {
|
|
37
|
+
logger.flush(deadlineMs);
|
|
38
|
+
} catch {
|
|
39
|
+
// A destination that cannot flush must not throw out of an AppState
|
|
40
|
+
// listener, where React Native has nowhere to put the exception.
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
} catch {
|
|
44
|
+
return () => {};
|
|
45
|
+
}
|
|
46
|
+
let removed = false;
|
|
47
|
+
return () => {
|
|
48
|
+
if (removed) return;
|
|
49
|
+
removed = true;
|
|
50
|
+
try {
|
|
51
|
+
subscription?.remove();
|
|
52
|
+
} catch {
|
|
53
|
+
// Already gone.
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* `AppState` without importing `react-native` at module load.
|
|
60
|
+
*
|
|
61
|
+
* A static import would make this module — and therefore the package entry
|
|
62
|
+
* point — unloadable anywhere React Native is not present, which includes the
|
|
63
|
+
* Node process the unit tests run in.
|
|
64
|
+
*/
|
|
65
|
+
function resolveAppState() {
|
|
66
|
+
try {
|
|
67
|
+
const rn = require('react-native');
|
|
68
|
+
const candidate = rn.AppState;
|
|
69
|
+
if (typeof candidate !== 'object' || candidate === null) return undefined;
|
|
70
|
+
const add = candidate.addEventListener;
|
|
71
|
+
return typeof add === 'function' ? candidate : undefined;
|
|
72
|
+
} catch {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function budget(value) {
|
|
77
|
+
if (value === undefined) return DEFAULT_DEADLINE_MS;
|
|
78
|
+
if (!Number.isFinite(value) || value < 0) return DEFAULT_DEADLINE_MS;
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=appState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Log","DEFAULT_DEADLINE_MS","LEAVING_FOREGROUND","Set","flushOnBackground","options","appState","resolveAppState","logger","deadlineMs","budget","subscription","addEventListener","state","has","flush","removed","remove","rn","require","candidate","AppState","undefined","add","value","Number","isFinite"],"sourceRoot":"../../../src","sources":["integrations/appState.ts"],"mappings":";;AACA,SAASA,GAAG,QAAQ,cAAW;;AAG/B;;AAwBA,MAAMC,mBAAmB,GAAG,IAAI;;AAEhC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,kBAAuC,GAAG,IAAIC,GAAG,CAAC,CACtD,UAAU,EACV,YAAY,CACb,CAAC;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,iBAAiBA,CAC/BC,OAAkC,EACvB;EACX,MAAMC,QAAQ,GAAGD,OAAO,EAAEC,QAAQ,IAAIC,eAAe,CAAC,CAAC;EACvD,IAAI,CAACD,QAAQ,EAAE,OAAO,MAAM,CAAC,CAAC;EAE9B,MAAME,MAAM,GAAGH,OAAO,EAAEG,MAAM,IAAIR,GAAG;EACrC,MAAMS,UAAU,GAAGC,MAAM,CAACL,OAAO,EAAEI,UAAU,CAAC;EAE9C,IAAIE,YAA4C;EAChD,IAAI;IACFA,YAAY,GAAGL,QAAQ,CAACM,gBAAgB,CAAC,QAAQ,EAAGC,KAAK,IAAK;MAC5D,IAAI,CAACX,kBAAkB,CAACY,GAAG,CAACD,KAAK,CAAC,EAAE;MACpC,IAAI;QACFL,MAAM,CAACO,KAAK,CAACN,UAAU,CAAC;MAC1B,CAAC,CAAC,MAAM;QACN;QACA;MAAA;IAEJ,CAAC,CAAC;EACJ,CAAC,CAAC,MAAM;IACN,OAAO,MAAM,CAAC,CAAC;EACjB;EAEA,IAAIO,OAAO,GAAG,KAAK;EACnB,OAAO,MAAM;IACX,IAAIA,OAAO,EAAE;IACbA,OAAO,GAAG,IAAI;IACd,IAAI;MACFL,YAAY,EAAEM,MAAM,CAAC,CAAC;IACxB,CAAC,CAAC,MAAM;MACN;IAAA;EAEJ,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASV,eAAeA,CAAA,EAA6B;EACnD,IAAI;IACF,MAAMW,EAAE,GAAGC,OAAO,CAAC,cAAc,CAA2B;IAC5D,MAAMC,SAAS,GAAGF,EAAE,CAACG,QAAQ;IAC7B,IAAI,OAAOD,SAAS,KAAK,QAAQ,IAAIA,SAAS,KAAK,IAAI,EAAE,OAAOE,SAAS;IACzE,MAAMC,GAAG,GAAIH,SAAS,CAAoCR,gBAAgB;IAC1E,OAAO,OAAOW,GAAG,KAAK,UAAU,GAAIH,SAAS,GAAoBE,SAAS;EAC5E,CAAC,CAAC,MAAM;IACN,OAAOA,SAAS;EAClB;AACF;AAEA,SAASZ,MAAMA,CAACc,KAAyB,EAAU;EACjD,IAAIA,KAAK,KAAKF,SAAS,EAAE,OAAOrB,mBAAmB;EACnD,IAAI,CAACwB,MAAM,CAACC,QAAQ,CAACF,KAAK,CAAC,IAAIA,KAAK,GAAG,CAAC,EAAE,OAAOvB,mBAAmB;EACpE,OAAOuB,KAAK;AACd","ignoreList":[]}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { Log } from "../Logger.js";
|
|
4
|
+
import { pub } from "../privacy.js";
|
|
5
|
+
import { sanitizeError } from "./sanitizeError.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* React Native's global error hook.
|
|
9
|
+
*
|
|
10
|
+
* `ErrorUtils` is undocumented and has been de-facto stable for a decade, which
|
|
11
|
+
* is the whole risk: it is typed here rather than imported so the library never
|
|
12
|
+
* depends on a declaration file that may not exist, and every access is
|
|
13
|
+
* guarded so a runtime without it degrades to doing nothing.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Metadata keys this handler writes. Add them to a strict key catalog. */
|
|
17
|
+
export const ERROR_METADATA_KEYS = ['errorName', 'errorMessage', 'errorFrames', 'errorFrameCount', 'errorFramesTruncated', 'fatal'];
|
|
18
|
+
|
|
19
|
+
/** The message this handler logs. A literal, as the lint rule requires. */
|
|
20
|
+
export const UNCAUGHT_ERROR_MESSAGE = 'uncaught error';
|
|
21
|
+
const DEFAULT_FATAL_FLUSH_MS = 2000;
|
|
22
|
+
|
|
23
|
+
/** Undoes an install. Idempotent; safe to call after another handler took over. */
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Logs uncaught errors, flushes on fatal ones, and hands the error onward.
|
|
27
|
+
*
|
|
28
|
+
* The flush is the reason this exists. A crash is precisely when the buffered
|
|
29
|
+
* entries explaining it are still in memory, and precisely when nothing will
|
|
30
|
+
* come along later to write them.
|
|
31
|
+
*
|
|
32
|
+
* Nothing about the error is trusted — see {@link sanitizeError}. What reaches
|
|
33
|
+
* the log is a built-in class name, a redacted message outside dev, and stack
|
|
34
|
+
* positions in files whose names were already known.
|
|
35
|
+
*/
|
|
36
|
+
export function installErrorHandler(options) {
|
|
37
|
+
const errorUtils = options?.errorUtils ?? globalErrorUtils();
|
|
38
|
+
if (!errorUtils) {
|
|
39
|
+
// No hook on this runtime — a bare Node test, a web target. Returning a
|
|
40
|
+
// no-op uninstall keeps the caller's teardown symmetrical either way.
|
|
41
|
+
return () => {};
|
|
42
|
+
}
|
|
43
|
+
const logger = options?.logger ?? Log;
|
|
44
|
+
const chain = options?.chain ?? true;
|
|
45
|
+
const fatalFlushMs = flushBudget(options?.fatalFlushMs);
|
|
46
|
+
const previous = readPrevious(errorUtils);
|
|
47
|
+
const handler = (error, isFatal) => {
|
|
48
|
+
// Uninstalled, but still the installed handler: something installed over
|
|
49
|
+
// us and then restored us on its way out. Pass straight through rather
|
|
50
|
+
// than logging to a logger the caller has finished with.
|
|
51
|
+
if (INSTALLED.get(handler)?.active !== true) {
|
|
52
|
+
liveHandler(previous)?.(error, isFatal);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Every step is isolated. A handler that throws while reporting a crash
|
|
57
|
+
// replaces a diagnosable failure with an undiagnosable one, and takes the
|
|
58
|
+
// previous handler — the RedBox, the crash reporter — down with it.
|
|
59
|
+
try {
|
|
60
|
+
const sanitized = sanitizeError(error, options);
|
|
61
|
+
logger.error(UNCAUGHT_ERROR_MESSAGE, {
|
|
62
|
+
errorName: pub(sanitized.name),
|
|
63
|
+
errorMessage: pub(sanitized.message),
|
|
64
|
+
errorFrames: pub(sanitized.frames.join(' | ')),
|
|
65
|
+
// Wrapped for the same reason as the three above, and it was an
|
|
66
|
+
// oversight that they were not: every one of these is generated
|
|
67
|
+
// here, from a count, a flag this function was handed, and a
|
|
68
|
+
// decision this module made. None can carry caller data. Left bare
|
|
69
|
+
// they follow the privacy default, so under `privacyDefault('private')`
|
|
70
|
+
// a crash report renders `fatal: <private>` — which withholds
|
|
71
|
+
// nothing, because there was nothing to withhold, and costs the
|
|
72
|
+
// reader the one field that says whether the app is still running.
|
|
73
|
+
errorFrameCount: pub(sanitized.frameCount),
|
|
74
|
+
errorFramesTruncated: pub(sanitized.framesTruncated),
|
|
75
|
+
fatal: pub(isFatal === true)
|
|
76
|
+
}, options?.subsystem);
|
|
77
|
+
} catch {
|
|
78
|
+
// Reporting failed; the flush and the chain below still matter.
|
|
79
|
+
}
|
|
80
|
+
if (isFatal) {
|
|
81
|
+
try {
|
|
82
|
+
logger.flush(fatalFlushMs);
|
|
83
|
+
} catch {
|
|
84
|
+
// A destination that cannot flush must not stop the crash from
|
|
85
|
+
// reaching the handler that shows it.
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (chain) {
|
|
89
|
+
liveHandler(previous)?.(error, isFatal);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
INSTALLED.set(handler, {
|
|
93
|
+
active: true,
|
|
94
|
+
previous
|
|
95
|
+
});
|
|
96
|
+
errorUtils.setGlobalHandler(handler);
|
|
97
|
+
return () => {
|
|
98
|
+
const state = INSTALLED.get(handler);
|
|
99
|
+
if (!state || !state.active) return;
|
|
100
|
+
|
|
101
|
+
// Marked dead first, and unconditionally. Uninstalling out of order is
|
|
102
|
+
// ordinary — two libraries, a hot reload — and if this only took effect
|
|
103
|
+
// when ours happened to be the current handler, a later uninstall that
|
|
104
|
+
// restored us would bring a logger back to life that its owner had
|
|
105
|
+
// already let go of.
|
|
106
|
+
state.active = false;
|
|
107
|
+
|
|
108
|
+
// Something else is installed over us. Leave it alone: putting `previous`
|
|
109
|
+
// back would silently uninstall theirs. The flag above makes our wrapper
|
|
110
|
+
// inert if they ever restore it.
|
|
111
|
+
if (readPrevious(errorUtils) !== handler) return;
|
|
112
|
+
errorUtils.setGlobalHandler(liveHandler(state.previous) ?? (() => {}));
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The handlers this module installed, and whether each is still live.
|
|
117
|
+
*
|
|
118
|
+
* A WeakMap rather than a property on the function: the entry disappears with
|
|
119
|
+
* the handler, and nothing about our bookkeeping is visible to code that
|
|
120
|
+
* inspects the global handler.
|
|
121
|
+
*/
|
|
122
|
+
const INSTALLED = new WeakMap();
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The first handler in the chain that is still installed.
|
|
126
|
+
*
|
|
127
|
+
* Walks past our own uninstalled wrappers. Any handler we did not install is
|
|
128
|
+
* live by definition — we have no way to know otherwise, and assuming it is
|
|
129
|
+
* gone would drop the RedBox or a crash reporter.
|
|
130
|
+
*/
|
|
131
|
+
function liveHandler(handler) {
|
|
132
|
+
const seen = new Set();
|
|
133
|
+
let candidate = handler;
|
|
134
|
+
while (candidate) {
|
|
135
|
+
const state = INSTALLED.get(candidate);
|
|
136
|
+
if (!state || state.active) return candidate;
|
|
137
|
+
// A cycle needs two of our own handlers pointing at each other, which
|
|
138
|
+
// takes a restore we did not do — but the crash path is the wrong place
|
|
139
|
+
// to find out the hard way.
|
|
140
|
+
if (seen.has(candidate)) return undefined;
|
|
141
|
+
seen.add(candidate);
|
|
142
|
+
candidate = state.previous;
|
|
143
|
+
}
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
function readPrevious(errorUtils) {
|
|
147
|
+
try {
|
|
148
|
+
return errorUtils.getGlobalHandler?.();
|
|
149
|
+
} catch {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** The global `ErrorUtils`, if this runtime has one. */
|
|
155
|
+
function globalErrorUtils() {
|
|
156
|
+
const candidate = globalThis.ErrorUtils;
|
|
157
|
+
if (typeof candidate !== 'object' || candidate === null) return undefined;
|
|
158
|
+
const setter = candidate.setGlobalHandler;
|
|
159
|
+
return typeof setter === 'function' ? candidate : undefined;
|
|
160
|
+
}
|
|
161
|
+
function flushBudget(value) {
|
|
162
|
+
if (value === undefined) return DEFAULT_FATAL_FLUSH_MS;
|
|
163
|
+
if (!Number.isFinite(value) || value < 0) return DEFAULT_FATAL_FLUSH_MS;
|
|
164
|
+
return value;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=errorHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Log","pub","sanitizeError","ERROR_METADATA_KEYS","UNCAUGHT_ERROR_MESSAGE","DEFAULT_FATAL_FLUSH_MS","installErrorHandler","options","errorUtils","globalErrorUtils","logger","chain","fatalFlushMs","flushBudget","previous","readPrevious","handler","error","isFatal","INSTALLED","get","active","liveHandler","sanitized","errorName","name","errorMessage","message","errorFrames","frames","join","errorFrameCount","frameCount","errorFramesTruncated","framesTruncated","fatal","subsystem","flush","set","setGlobalHandler","state","WeakMap","seen","Set","candidate","has","undefined","add","getGlobalHandler","globalThis","ErrorUtils","setter","value","Number","isFinite"],"sourceRoot":"../../../src","sources":["integrations/errorHandler.ts"],"mappings":"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","ignoreList":[]}
|