feat(utils): add structured error logging to Result.wrap
Integrate the Logger into `Result.wrap` so that caught exceptions are recorded with stack trace, error type, and a `component: "Result"` tag before being wrapped into a `Result<T>`. Errors are first normalized via `toError` to preserve `.stack`, `.code`, and `.status` fields, then logged through the standard pipeline (dev console in development, JSON pipeline in production). Callers continue to receive a `Result<T>` — re-throwing remains opt-in via `Result.unwrap`.
This commit is contained in:
+18
-1
@@ -14,10 +14,15 @@
|
|||||||
* (`ApiError extends Error`),仓库 `Result.wrap` 捕获后用 `toError` 规范化,
|
* (`ApiError extends Error`),仓库 `Result.wrap` 捕获后用 `toError` 规范化,
|
||||||
* 调用方能可靠地 `instanceof ApiError` / `error.message` 访问错误信息。
|
* 调用方能可靠地 `instanceof ApiError` / `error.message` 访问错误信息。
|
||||||
*/
|
*/
|
||||||
|
import { Logger } from "./logger";
|
||||||
|
|
||||||
export type Result<T> =
|
export type Result<T> =
|
||||||
| { readonly success: true; readonly data: T }
|
| { readonly success: true; readonly data: T }
|
||||||
| { readonly success: false; readonly error: Error };
|
| { readonly success: false; readonly error: Error };
|
||||||
|
|
||||||
|
/** 仓库层 Result.wrap 专用 logger —— 自动带 component: "Result" 标签 */
|
||||||
|
const log = new Logger("Result");
|
||||||
|
|
||||||
export const Result = {
|
export const Result = {
|
||||||
/** 构造成功结果。 */
|
/** 构造成功结果。 */
|
||||||
ok<T>(data: T): Result<T> {
|
ok<T>(data: T): Result<T> {
|
||||||
@@ -49,12 +54,24 @@ export const Result = {
|
|||||||
/**
|
/**
|
||||||
* 捕获异步 thunk 的异常并包装成 `Result<T>`。仓库内主要用这个把
|
* 捕获异步 thunk 的异常并包装成 `Result<T>`。仓库内主要用这个把
|
||||||
* `*Api` 调用从「throw 风格」桥接到「Result 风格」。
|
* `*Api` 调用从「throw 风格」桥接到「Result 风格」。
|
||||||
|
*
|
||||||
|
* 错误处理策略(重点):
|
||||||
|
* 1. 捕获后用 `toError` 规范化(保留 .stack / .code / .status 等字段)
|
||||||
|
* 2. **用 Logger 记录**(带 stack + component=Result 标签)—— 调试 dev 控制台可见,
|
||||||
|
* 生产环境走 JSON pipeline 接入日志平台
|
||||||
|
* 3. **不**重新抛出 —— 调用方拿到的永远是 `Result<T>`(throw 风格调用方可在
|
||||||
|
* 最外层显式 `throw Result.unwrap(r)`)
|
||||||
*/
|
*/
|
||||||
async wrap<T>(thunk: () => Promise<T>): Promise<Result<T>> {
|
async wrap<T>(thunk: () => Promise<T>): Promise<Result<T>> {
|
||||||
try {
|
try {
|
||||||
return Result.ok(await thunk());
|
return Result.ok(await thunk());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Result.err(e);
|
const err = toError(e);
|
||||||
|
log.error(
|
||||||
|
{ err, stack: err.stack, type: err.constructor.name },
|
||||||
|
"Result.wrap caught exception",
|
||||||
|
);
|
||||||
|
return Result.err(err);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
Reference in New Issue
Block a user