@namzu/sdk 29.0.0 → 30.0.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/CHANGELOG.md +50 -0
- package/README.md +57 -419
- package/dist/plugin/loader.d.ts.map +1 -1
- package/dist/plugin/loader.js +10 -12
- package/dist/plugin/loader.js.map +1 -1
- package/dist/public-runtime.d.ts +14 -1
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +14 -1
- package/dist/public-runtime.js.map +1 -1
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +10 -12
- package/dist/skills/loader.js.map +1 -1
- package/dist/utils/log/create-logger.d.ts +3 -3
- package/dist/utils/log/create-logger.d.ts.map +1 -1
- package/dist/utils/log/create-logger.js +10 -8
- package/dist/utils/log/create-logger.js.map +1 -1
- package/dist/utils/log/process-sink.d.ts +7 -4
- package/dist/utils/log/process-sink.d.ts.map +1 -1
- package/dist/utils/log/process-sink.js +19 -13
- package/dist/utils/log/process-sink.js.map +1 -1
- package/dist/utils/log/types.d.ts +12 -7
- package/dist/utils/log/types.d.ts.map +1 -1
- package/dist/utils/log/types.js +6 -6
- package/dist/utils/log/types.js.map +1 -1
- package/dist/utils/logger.d.ts +15 -35
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +18 -136
- package/dist/utils/logger.js.map +1 -1
- package/package.json +1 -1
- package/src/plugin/loader.ts +10 -12
- package/src/public-runtime.ts +14 -1
- package/src/skills/loader.ts +10 -12
- package/src/utils/log/create-logger.ts +10 -8
- package/src/utils/log/process-sink.ts +19 -13
- package/src/utils/log/types.ts +18 -13
- package/src/utils/logger.ts +18 -159
package/src/utils/logger.ts
CHANGED
|
@@ -1,24 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getProcessSink
|
|
1
|
+
import { NOOP_LOGGER } from './log/create-logger.js'
|
|
2
|
+
import { getProcessSink } from './log/process-sink.js'
|
|
3
3
|
import type { LogSinkCounters } from './log/types.js'
|
|
4
|
-
import { type LevelFilter, type LogSink, SCOPE_ATTRIBUTE } from './log/types.js'
|
|
5
4
|
|
|
6
5
|
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'
|
|
7
6
|
|
|
8
7
|
export type LogContext = Record<string, unknown>
|
|
9
8
|
|
|
10
|
-
const LOG_LEVELS: Record<LogLevel, number> = {
|
|
11
|
-
debug: 0,
|
|
12
|
-
info: 1,
|
|
13
|
-
warn: 2,
|
|
14
|
-
error: 3,
|
|
15
|
-
// `silent` sits above every emit level so the `level < minLevelNum`
|
|
16
|
-
// guard in `log()` always short-circuits when configured. Used by
|
|
17
|
-
// test harnesses to suppress unmocked `getRootLogger()` stderr
|
|
18
|
-
// writes; see packages/sdk/src/test-setup.ts.
|
|
19
|
-
silent: 4,
|
|
20
|
-
}
|
|
21
|
-
|
|
22
9
|
export interface Logger {
|
|
23
10
|
debug(message: string, data?: LogContext): void
|
|
24
11
|
info(message: string, data?: LogContext): void
|
|
@@ -27,88 +14,21 @@ export interface Logger {
|
|
|
27
14
|
child(context: LogContext): Logger
|
|
28
15
|
}
|
|
29
16
|
|
|
30
|
-
function createLoggerImpl(name: string, minLevel: LogLevel, parentContext: LogContext): Logger {
|
|
31
|
-
const minLevelNum = LOG_LEVELS[minLevel]
|
|
32
|
-
|
|
33
|
-
function log(level: LogLevel, message: string, data?: LogContext): void {
|
|
34
|
-
if (LOG_LEVELS[level] < minLevelNum) return
|
|
35
|
-
|
|
36
|
-
const timestamp = new Date().toISOString()
|
|
37
|
-
const prefix = `[${timestamp}] [${level.toUpperCase()}] [${name}]`
|
|
38
|
-
const merged = { ...parentContext, ...data }
|
|
39
|
-
const hasContext = Object.keys(merged).length > 0
|
|
40
|
-
|
|
41
|
-
if (hasContext) {
|
|
42
|
-
process.stderr.write(`${prefix} ${message} ${JSON.stringify(merged)}\n`)
|
|
43
|
-
} else {
|
|
44
|
-
process.stderr.write(`${prefix} ${message}\n`)
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function child(context: LogContext): Logger {
|
|
49
|
-
const { [SCOPE_ATTRIBUTE]: scopeOverride, ...rest } = context
|
|
50
|
-
return createLoggerImpl(typeof scopeOverride === 'string' ? scopeOverride : name, minLevel, {
|
|
51
|
-
...parentContext,
|
|
52
|
-
...rest,
|
|
53
|
-
})
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return {
|
|
57
|
-
debug: (msg, data) => log('debug', msg, data),
|
|
58
|
-
info: (msg, data) => log('info', msg, data),
|
|
59
|
-
warn: (msg, data) => log('warn', msg, data),
|
|
60
|
-
error: (msg, data) => log('error', msg, data),
|
|
61
|
-
child,
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
let _rootLogger: Logger | null = null
|
|
66
|
-
|
|
67
17
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// same reason the new pipeline reads its level per record: a logger handed
|
|
80
|
-
// out before `installProcessSink` ran would otherwise keep writing to
|
|
81
|
-
// stderr forever, which is the exact shape of the three frozen loaders
|
|
82
|
-
// this migration just fixed.
|
|
83
|
-
//
|
|
84
|
-
// This bridge is what lets the ~39 existing `getRootLogger()` call sites
|
|
85
|
-
// reach a host's sink without being rewritten in one commit. They keep the
|
|
86
|
-
// old interface and gain the new destination.
|
|
87
|
-
const installed = getProcessSink()
|
|
88
|
-
if (installed) return fromSink(installed.sink, installed.level)
|
|
89
|
-
|
|
90
|
-
if (!_rootLogger) {
|
|
91
|
-
_rootLogger = createLoggerImpl('namzu', 'info', {})
|
|
92
|
-
}
|
|
93
|
-
return _rootLogger
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Fall back to the process root only when nobody supplied their own. Kept
|
|
98
|
-
* here rather than inlined at each call site so a boundary that threads a
|
|
99
|
-
* host-supplied logger can stay entirely free of `getRootLogger()` itself.
|
|
100
|
-
* `RunContextFactory.buildLogger` was the first caller (LOG-07); LOG-10
|
|
101
|
-
* moved every remaining constructor across `packages/sdk/src` onto this
|
|
102
|
-
* same seam, so this function's own fallback is now the ONLY place in the
|
|
103
|
-
* package that reads the process-wide global outside a host's direct call
|
|
104
|
-
* to `getRootLogger()` itself. `getRootLoggerCount` in
|
|
105
|
-
* `scripts/log-standard.json` measures exactly that: it cannot reach zero
|
|
106
|
-
* while an optional, non-breaking fallback exists at all — removing the
|
|
107
|
-
* fallback (flipping the default to `NOOP_LOGGER`) is LOG-20's major, not
|
|
108
|
-
* this seam's.
|
|
18
|
+
* A logger that discards, when nobody supplied one.
|
|
19
|
+
*
|
|
20
|
+
* The fallback used to be a process-wide global, so a construction with no
|
|
21
|
+
* logger silently wrote to stderr — from a library, on a stream the host may
|
|
22
|
+
* be using for its own protocol. LOG-20 flipped it: a component given no
|
|
23
|
+
* logger produces nothing, and the drop is counted where `getLogCounters()`
|
|
24
|
+
* can read it.
|
|
25
|
+
*
|
|
26
|
+
* The seam stays rather than being inlined at each call site, so every
|
|
27
|
+
* constructor in the package expresses "logger optional" the same way and one
|
|
28
|
+
* line decides what optional means.
|
|
109
29
|
*/
|
|
110
30
|
export function resolveLogger(logger: Logger | undefined): Logger {
|
|
111
|
-
return logger ??
|
|
31
|
+
return logger ?? NOOP_LOGGER
|
|
112
32
|
}
|
|
113
33
|
|
|
114
34
|
/**
|
|
@@ -116,74 +36,13 @@ export function resolveLogger(logger: Logger | undefined): Logger {
|
|
|
116
36
|
* when no host has claimed the process's log destination.
|
|
117
37
|
*
|
|
118
38
|
* `undefined` is the honest answer for that case, not a zeroed set. With no
|
|
119
|
-
* sink installed
|
|
120
|
-
*
|
|
121
|
-
* nothing
|
|
122
|
-
*
|
|
123
|
-
* never measured" and happens to be the claim a reader most wants to trust.
|
|
39
|
+
* sink installed there is no pipeline, and therefore no redaction pass, no
|
|
40
|
+
* size caps and nothing to count -- reporting five zeros would read as
|
|
41
|
+
* "nothing was dropped, nothing was redacted", a stronger claim than "this
|
|
42
|
+
* was never measured" and the one a reader most wants to trust.
|
|
124
43
|
* `namzu doctor`'s `logging.pipeline` check turns the absence into its own
|
|
125
44
|
* row rather than into a clean bill of health.
|
|
126
45
|
*/
|
|
127
46
|
export function getLogCounters(): LogSinkCounters | undefined {
|
|
128
47
|
return getProcessSink()?.counters
|
|
129
48
|
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Adapts the record pipeline back to the legacy `Logger` shape. `scope`
|
|
133
|
-
* threads through recursive `child()` calls the same way `bound` does.
|
|
134
|
-
* Previously fixed at `'namzu'` on every recursive call regardless of what
|
|
135
|
-
* a caller bound — meaning every `getRootLogger()`-derived child logger
|
|
136
|
-
* (the majority of call sites in this package) reported the SAME
|
|
137
|
-
* `scope.name` no matter what `SCOPE_ATTRIBUTE` it was given. This is the
|
|
138
|
-
* single highest-leverage line in the LOG-09 migration: see the direct
|
|
139
|
-
* regression test in `runtime/query/__tests__/context.test.ts` and
|
|
140
|
-
* `utils/__tests__/log-scope-attribute.test.ts`.
|
|
141
|
-
*/
|
|
142
|
-
function fromSink(
|
|
143
|
-
sink: LogSink,
|
|
144
|
-
level: LevelFilter,
|
|
145
|
-
bound: LogContext = {},
|
|
146
|
-
scope = 'namzu',
|
|
147
|
-
): Logger {
|
|
148
|
-
// The process's counter set, not a fresh one. `getRootLogger` resolves
|
|
149
|
-
// PER CALL and lands here every time, so a logger built with its own
|
|
150
|
-
// counters would throw the totals away between one log line and the
|
|
151
|
-
// next -- which is what made `LogSinkCounters` unreadable by anything.
|
|
152
|
-
const created = createLogger(
|
|
153
|
-
{
|
|
154
|
-
sink,
|
|
155
|
-
level: { current: level },
|
|
156
|
-
resource: { 'service.name': 'namzu' },
|
|
157
|
-
scope,
|
|
158
|
-
},
|
|
159
|
-
getProcessSinkCounters(),
|
|
160
|
-
)
|
|
161
|
-
const write =
|
|
162
|
-
(severity: 'debug' | 'info' | 'warn' | 'error') => (message: string, data?: LogContext) => {
|
|
163
|
-
created[severity](message, { ...bound, ...data })
|
|
164
|
-
}
|
|
165
|
-
return {
|
|
166
|
-
debug: write('debug'),
|
|
167
|
-
info: write('info'),
|
|
168
|
-
warn: write('warn'),
|
|
169
|
-
error: write('error'),
|
|
170
|
-
child: (context: LogContext) => {
|
|
171
|
-
const { [SCOPE_ATTRIBUTE]: scopeOverride, ...rest } = context
|
|
172
|
-
return fromSink(
|
|
173
|
-
sink,
|
|
174
|
-
level,
|
|
175
|
-
{ ...bound, ...rest },
|
|
176
|
-
typeof scopeOverride === 'string' ? scopeOverride : scope,
|
|
177
|
-
)
|
|
178
|
-
},
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* @deprecated See `getRootLogger`'s deprecation note. `installProcessSink`
|
|
184
|
-
* is the strictly more capable replacement — it picks a destination, not
|
|
185
|
-
* only a threshold. Unchanged behaviour; this JSDoc is the only edit.
|
|
186
|
-
*/
|
|
187
|
-
export function configureLogger(options: { level?: LogLevel }): void {
|
|
188
|
-
_rootLogger = createLoggerImpl('namzu', options.level ?? 'info', {})
|
|
189
|
-
}
|