@likec4/log 1.21.1 → 1.22.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/README.md +34 -1
- package/dist/index.cjs +167 -1528
- package/dist/index.d.cts +17 -464
- package/dist/index.d.mts +17 -464
- package/dist/index.d.ts +17 -464
- package/dist/index.mjs +156 -1507
- package/package.json +7 -17
- package/src/formatters.ts +201 -0
- package/src/index.ts +84 -32
- package/src/utils.ts +37 -0
- package/dist/browser.cjs +0 -1938
- package/dist/browser.mjs +0 -1932
- package/dist/chunks/prompt.cjs +0 -288
- package/dist/chunks/prompt.mjs +0 -280
- package/src/browser.ts +0 -16
- package/src/format.ts +0 -60
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@likec4/log",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.22.1",
|
|
5
5
|
"bugs": "https://github.com/likec4/likec4/issues",
|
|
6
6
|
"homepage": "https://likec4.dev",
|
|
7
7
|
"author": "Denis Davydkov <denis@davydkov.com>",
|
|
@@ -18,23 +18,10 @@
|
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
20
20
|
"sources": "./src/index.ts",
|
|
21
|
-
"
|
|
21
|
+
"default": {
|
|
22
22
|
"types": "./dist/index.d.ts",
|
|
23
23
|
"import": "./dist/index.mjs",
|
|
24
24
|
"require": "./dist/index.cjs"
|
|
25
|
-
},
|
|
26
|
-
"default": {
|
|
27
|
-
"types": "./dist/index.d.ts",
|
|
28
|
-
"import": "./dist/browser.mjs",
|
|
29
|
-
"require": "./dist/browser.cjs"
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
"./browser": {
|
|
33
|
-
"sources": "./src/browser.ts",
|
|
34
|
-
"default": {
|
|
35
|
-
"types": "./dist/index.d.ts",
|
|
36
|
-
"import": "./dist/browser.mjs",
|
|
37
|
-
"require": "./dist/browser.cjs"
|
|
38
25
|
}
|
|
39
26
|
}
|
|
40
27
|
},
|
|
@@ -46,9 +33,12 @@
|
|
|
46
33
|
"typecheck": "tsc --noEmit",
|
|
47
34
|
"build": "unbuild"
|
|
48
35
|
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@logtape/logtape": "^0.8.2"
|
|
38
|
+
},
|
|
49
39
|
"devDependencies": {
|
|
50
|
-
"@likec4/tsconfig": "1.
|
|
51
|
-
"@types/node": "^20.17.
|
|
40
|
+
"@likec4/tsconfig": "1.22.1",
|
|
41
|
+
"@types/node": "^20.17.17",
|
|
52
42
|
"consola": "^3.4.0",
|
|
53
43
|
"merge-error-cause": "^5.0.0",
|
|
54
44
|
"safe-stringify": "^1.1.1",
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type AnsiColorFormatterOptions,
|
|
3
|
+
type ConsoleSinkOptions,
|
|
4
|
+
type FormattedValues,
|
|
5
|
+
type LogLevel,
|
|
6
|
+
type LogRecord,
|
|
7
|
+
type Sink,
|
|
8
|
+
type TextFormatter,
|
|
9
|
+
type TextFormatterOptions,
|
|
10
|
+
getAnsiColorFormatter as getLogtapeAnsiColorFormatter,
|
|
11
|
+
getConsoleSink as getLogtapeConsoleSink,
|
|
12
|
+
getTextFormatter as getLogtapeTextFormatter,
|
|
13
|
+
} from '@logtape/logtape'
|
|
14
|
+
import mergeErrorCause from 'merge-error-cause'
|
|
15
|
+
import wrapErrorMessage from 'wrap-error-message'
|
|
16
|
+
import { ident, parseStack } from './utils'
|
|
17
|
+
|
|
18
|
+
// export function formatProperties(properties: Record<string, unknown>): {
|
|
19
|
+
// properties: Record<string, unknown>
|
|
20
|
+
// output?: string
|
|
21
|
+
// error?: never
|
|
22
|
+
// } | {
|
|
23
|
+
// properties: Record<string, unknown>
|
|
24
|
+
// output: string
|
|
25
|
+
// error?: {
|
|
26
|
+
// message: string
|
|
27
|
+
// name: string
|
|
28
|
+
// stack?: string
|
|
29
|
+
// }
|
|
30
|
+
// } {
|
|
31
|
+
// let error: {
|
|
32
|
+
// message: string
|
|
33
|
+
// name: string
|
|
34
|
+
// stack?: string
|
|
35
|
+
// } | undefined
|
|
36
|
+
// let totalProps = 0
|
|
37
|
+
// const formattedProperties = {} as Record<string, unknown>
|
|
38
|
+
// for (const [key, value] of Object.entries(properties)) {
|
|
39
|
+
// if (value instanceof Error) {
|
|
40
|
+
// const mergedErr = mergeErrorCause(value)
|
|
41
|
+
// const stack = mergedErr.stack ? parseStack(mergedErr.stack) : undefined
|
|
42
|
+
// const formattedError = {
|
|
43
|
+
// message: mergedErr.message,
|
|
44
|
+
// name: mergedErr.name,
|
|
45
|
+
// ...stack && { stack: stack.join('\n') },
|
|
46
|
+
// }
|
|
47
|
+
// error ??= formattedError
|
|
48
|
+
// formattedProperties[key] = formattedError
|
|
49
|
+
// } else {
|
|
50
|
+
// formattedProperties[key] = value
|
|
51
|
+
// }
|
|
52
|
+
// totalProps++
|
|
53
|
+
// }
|
|
54
|
+
// if (totalProps === 0) {
|
|
55
|
+
// return {
|
|
56
|
+
// properties: formattedProperties,
|
|
57
|
+
// }
|
|
58
|
+
// }
|
|
59
|
+
// if (error) {
|
|
60
|
+
// return {
|
|
61
|
+
// error: error,
|
|
62
|
+
// output: error.stack ? error.message + '\n' + ident(error.stack.slice(1)) : error.message,
|
|
63
|
+
// properties: formattedProperties,
|
|
64
|
+
// }
|
|
65
|
+
// }
|
|
66
|
+
// return {
|
|
67
|
+
// ...(error && { error: error }),
|
|
68
|
+
// output: safeStringify(formattedProperties, { indentation: '\t' }),
|
|
69
|
+
// properties: formattedProperties,
|
|
70
|
+
// }
|
|
71
|
+
// }
|
|
72
|
+
|
|
73
|
+
function gerErrorFromLogRecord(record: LogRecord): Error | null {
|
|
74
|
+
const errors = Object
|
|
75
|
+
.values(record.properties)
|
|
76
|
+
.filter((v) => v instanceof Error)
|
|
77
|
+
.map(err => {
|
|
78
|
+
const mergedErr = mergeErrorCause(err)
|
|
79
|
+
if (mergedErr.stack) {
|
|
80
|
+
mergedErr.stack = parseStack(mergedErr.stack).join('\n')
|
|
81
|
+
}
|
|
82
|
+
return mergedErr
|
|
83
|
+
})
|
|
84
|
+
if (errors.length === 0) {
|
|
85
|
+
return null
|
|
86
|
+
}
|
|
87
|
+
return errors.length === 1 ? errors[0]! : new AggregateError(errors)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function errorFromLogRecord(record: LogRecord): Error | null {
|
|
91
|
+
const error = gerErrorFromLogRecord(record)
|
|
92
|
+
if (error && typeof record.rawMessage === 'string') {
|
|
93
|
+
return wrapErrorMessage(error, record.rawMessage + '\n')
|
|
94
|
+
}
|
|
95
|
+
return error
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function appendErrorToMessage(values: FormattedValues, color?: boolean): FormattedValues {
|
|
99
|
+
const error = gerErrorFromLogRecord(values.record)
|
|
100
|
+
if (error) {
|
|
101
|
+
let errorMessge = error.message
|
|
102
|
+
if (error.stack) {
|
|
103
|
+
errorMessge = errorMessge + '\n' + ident(error.stack.split('\n').slice(1))
|
|
104
|
+
}
|
|
105
|
+
if (color) {
|
|
106
|
+
errorMessge = `${ansiColors.red}${errorMessge}${RESET}`
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
...values,
|
|
110
|
+
message: values.message + '\n' + ident(errorMessge),
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return values
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// export function formatRecord(values: FormattedValues): FormattedValues {
|
|
117
|
+
// const props = formatProperties(values.record.properties)
|
|
118
|
+
// if (props.output) {
|
|
119
|
+
// props.output = ' \n' + ident(props.output)
|
|
120
|
+
// return {
|
|
121
|
+
// ...values,
|
|
122
|
+
// record: {
|
|
123
|
+
// ...values.record,
|
|
124
|
+
// properties: props.properties,
|
|
125
|
+
// },
|
|
126
|
+
// message: `${values.message}${props.output}`,
|
|
127
|
+
// }
|
|
128
|
+
// }
|
|
129
|
+
// return values
|
|
130
|
+
// }
|
|
131
|
+
|
|
132
|
+
const levelAbbreviations: Record<LogLevel, string> = {
|
|
133
|
+
'debug': 'DEBUG',
|
|
134
|
+
'info': 'INFO ',
|
|
135
|
+
'warning': 'WARN ',
|
|
136
|
+
'error': 'ERROR',
|
|
137
|
+
'fatal': 'FATAL',
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function getMessageOnlyFormatter(): TextFormatter {
|
|
141
|
+
return getTextFormatter({
|
|
142
|
+
format: ({ message }): string => {
|
|
143
|
+
return message
|
|
144
|
+
},
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const level = (l: LogLevel): string => levelAbbreviations[l]
|
|
149
|
+
|
|
150
|
+
export function getTextFormatter(options?: TextFormatterOptions): TextFormatter {
|
|
151
|
+
const _format = options?.format ?? (({ timestamp, level, category, message }: FormattedValues): string => {
|
|
152
|
+
return `${timestamp} ${level} ${category} ${message}`
|
|
153
|
+
})
|
|
154
|
+
// const format = options?.format
|
|
155
|
+
return getLogtapeTextFormatter({
|
|
156
|
+
timestamp: 'time',
|
|
157
|
+
level,
|
|
158
|
+
category: '.',
|
|
159
|
+
...options,
|
|
160
|
+
format: (values) => {
|
|
161
|
+
return _format(appendErrorToMessage(values))
|
|
162
|
+
},
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const RESET = '\x1b[0m'
|
|
167
|
+
|
|
168
|
+
const ansiColors = {
|
|
169
|
+
// black: "\x1b[30m",
|
|
170
|
+
red: '\x1b[31m',
|
|
171
|
+
// green: "\x1b[32m",
|
|
172
|
+
// yellow: "\x1b[33m",
|
|
173
|
+
// blue: "\x1b[34m",
|
|
174
|
+
// magenta: "\x1b[35m",
|
|
175
|
+
// cyan: "\x1b[36m",
|
|
176
|
+
// white: "\x1b[37m",
|
|
177
|
+
} as const
|
|
178
|
+
|
|
179
|
+
export function getAnsiColorFormatter(options?: AnsiColorFormatterOptions): TextFormatter {
|
|
180
|
+
const _format = options?.format ?? (({ timestamp, level, category, message }: FormattedValues): string => {
|
|
181
|
+
return `${timestamp} ${level} ${category} ${message}`
|
|
182
|
+
})
|
|
183
|
+
return getLogtapeAnsiColorFormatter({
|
|
184
|
+
timestamp: 'time',
|
|
185
|
+
level,
|
|
186
|
+
categoryStyle: 'bold',
|
|
187
|
+
categoryColor: 'cyan',
|
|
188
|
+
category: '.',
|
|
189
|
+
...options,
|
|
190
|
+
format: (values) => {
|
|
191
|
+
return _format(appendErrorToMessage(values, true))
|
|
192
|
+
},
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function getConsoleSink(options?: ConsoleSinkOptions): Sink {
|
|
197
|
+
return getLogtapeConsoleSink({
|
|
198
|
+
formatter: getAnsiColorFormatter(),
|
|
199
|
+
...options,
|
|
200
|
+
})
|
|
201
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,36 +1,88 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export type {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
import {
|
|
2
|
+
type Config,
|
|
3
|
+
configure as configureLogtape,
|
|
4
|
+
getLogger,
|
|
5
|
+
} from '@logtape/logtape'
|
|
6
|
+
import { getConsoleSink } from './formatters'
|
|
7
|
+
|
|
8
|
+
export type {
|
|
9
|
+
Filter,
|
|
10
|
+
Logger,
|
|
11
|
+
LogLevel,
|
|
12
|
+
LogRecord,
|
|
13
|
+
Sink,
|
|
14
|
+
TextFormatter,
|
|
15
|
+
} from '@logtape/logtape'
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
errorFromLogRecord,
|
|
19
|
+
// formatProperties,
|
|
20
|
+
// formatRecord,
|
|
21
|
+
getAnsiColorFormatter,
|
|
22
|
+
getConsoleSink,
|
|
23
|
+
getMessageOnlyFormatter,
|
|
24
|
+
getTextFormatter,
|
|
25
|
+
} from './formatters'
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
withFilter,
|
|
29
|
+
} from '@logtape/logtape'
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
logger as consola,
|
|
33
|
+
logger as rootLogger,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
loggable,
|
|
38
|
+
} from './utils'
|
|
39
|
+
|
|
40
|
+
export const logger = getLogger('likec4')
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get a child logger with the given subcategory.
|
|
44
|
+
*
|
|
45
|
+
* @param subcategory The subcategory.
|
|
46
|
+
* @returns The child logger.
|
|
47
|
+
*/
|
|
48
|
+
export function createLogger(subcategory: string | readonly [string] | readonly [string, ...string[]]) {
|
|
49
|
+
return logger.getChild(subcategory)
|
|
14
50
|
}
|
|
15
51
|
|
|
16
|
-
|
|
17
|
-
|
|
52
|
+
let configureWasCalled = false
|
|
53
|
+
|
|
54
|
+
export async function configureLogger<TSinkId extends string, TFilterId extends string>(
|
|
55
|
+
config?: Config<TSinkId, TFilterId>,
|
|
56
|
+
) {
|
|
57
|
+
try {
|
|
58
|
+
configureWasCalled = true
|
|
59
|
+
const sinks = config?.sinks ?? {}
|
|
60
|
+
await configureLogtape<any, any>({
|
|
61
|
+
...config,
|
|
62
|
+
sinks: {
|
|
63
|
+
...sinks,
|
|
64
|
+
// @ts-expect-error console is not a valid sink id
|
|
65
|
+
console: sinks['console'] ?? getConsoleSink(),
|
|
66
|
+
},
|
|
67
|
+
loggers: [
|
|
68
|
+
{ category: ['logtape', 'meta'], sinks: ['console' as any], lowestLevel: 'warning' },
|
|
69
|
+
...(config?.loggers ?? [
|
|
70
|
+
{
|
|
71
|
+
category: 'likec4',
|
|
72
|
+
sinks: ['console' as any],
|
|
73
|
+
lowestLevel: 'debug',
|
|
74
|
+
},
|
|
75
|
+
]),
|
|
76
|
+
],
|
|
77
|
+
})
|
|
78
|
+
} catch (e) {
|
|
79
|
+
console.error(e)
|
|
80
|
+
}
|
|
18
81
|
}
|
|
19
82
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
},
|
|
27
|
-
throttle: 2,
|
|
28
|
-
throttleMin: 500,
|
|
29
|
-
formatOptions: {
|
|
30
|
-
colors: true,
|
|
31
|
-
compact: false,
|
|
32
|
-
date: false,
|
|
33
|
-
},
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
export { consola, consola as logger, consola as rootLogger, LogLevels }
|
|
83
|
+
export function ensureLoggerIsConfigured() {
|
|
84
|
+
if (!configureWasCalled) {
|
|
85
|
+
configureLogger()
|
|
86
|
+
console.warn('logger automatically configured with default settings')
|
|
87
|
+
}
|
|
88
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import mergeErrorCause from 'merge-error-cause'
|
|
2
|
+
import safeStringify from 'safe-stringify'
|
|
3
|
+
|
|
4
|
+
export const parseStack = (stack: string): string[] => {
|
|
5
|
+
const lines = stack
|
|
6
|
+
.split('\n')
|
|
7
|
+
.map((l) => {
|
|
8
|
+
let replaced = l.trim()
|
|
9
|
+
.replace('file://', '')
|
|
10
|
+
// // Remove c:\Users\<user>... -> @vscode...
|
|
11
|
+
// .replace(/[A-Za-z]:\\Users\\[^\\]+\\/g, '@vscode\\')
|
|
12
|
+
// // Remove /Users/<user>/... -> @vscode/...
|
|
13
|
+
// .replace(/\/Users\/[^/]+\//g, '@vscode/')
|
|
14
|
+
return replaced
|
|
15
|
+
})
|
|
16
|
+
return lines
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function ident(value: string | string[], identation = 2): string {
|
|
20
|
+
value = Array.isArray(value) ? value : value.split('\n')
|
|
21
|
+
return value.map((l) => `${' '.repeat(identation)}${l}`).join('\n')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function loggable(error: unknown): string {
|
|
25
|
+
if (typeof error === 'string') {
|
|
26
|
+
return error
|
|
27
|
+
}
|
|
28
|
+
if (error instanceof Error) {
|
|
29
|
+
const mergedErr = mergeErrorCause(error)
|
|
30
|
+
if (mergedErr.stack) {
|
|
31
|
+
const stack = parseStack(mergedErr.stack)
|
|
32
|
+
return mergedErr.message + '\n' + ident(stack.slice(1))
|
|
33
|
+
}
|
|
34
|
+
return mergedErr.message
|
|
35
|
+
}
|
|
36
|
+
return safeStringify(error)
|
|
37
|
+
}
|