Skip to content

Commit a4cc060

Browse files
committed
feat: enhance task handlers with logging and performance monitoring using Fastify's request.log for improved observability in backend-nodejs
1 parent 0199645 commit a4cc060

File tree

16 files changed

+669
-218
lines changed

16 files changed

+669
-218
lines changed

backend-nodejs/domains/task/handlers/complete_task.handler.ts

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,53 @@ import { createContextFromRequest } from '../../../shared/types/context.js';
1111
/**
1212
* CompleteTask Handler
1313
* HTTP 适配层:处理完成任务的 HTTP 请求
14+
* 负责日志记录和性能监控,使用 Fastify 的 request.log(自动包含请求上下文)
1415
* 错误由全局错误处理中间件统一处理
1516
*/
1617
export async function completeTaskHandler(
1718
deps: HandlerDependencies,
1819
req: FastifyRequest<{ Params: { id: string } }>,
1920
reply: FastifyReply
2021
): Promise<void> {
22+
const startTime = Date.now();
2123
const userId = requireUserId(req);
2224
const taskId = req.params.id;
2325

24-
const input = toCompleteTaskInput(userId, taskId);
25-
const ctx = createContextFromRequest({ userId, ...req });
26-
const output = await deps.taskService.completeTask(ctx, input);
26+
req.log.info({
27+
taskId,
28+
userId,
29+
}, 'Completing task');
2730

28-
reply.code(200).send(toCompleteTaskResponse(output.task));
31+
try {
32+
const input = toCompleteTaskInput(userId, taskId);
33+
const ctx = createContextFromRequest({ userId, ...req });
34+
const output = await deps.taskService.completeTask(ctx, input);
35+
36+
const duration = Date.now() - startTime;
37+
req.log.info({
38+
taskId: output.task.id,
39+
userId: output.task.userId,
40+
duration,
41+
}, 'Task completed successfully');
42+
43+
if (duration > 1000) {
44+
req.log.warn({
45+
taskId: output.task.id,
46+
duration,
47+
threshold: 1000,
48+
}, 'Slow task completion');
49+
}
50+
51+
reply.code(200).send(toCompleteTaskResponse(output.task));
52+
} catch (error) {
53+
const duration = Date.now() - startTime;
54+
req.log.error({
55+
taskId,
56+
userId,
57+
duration,
58+
error: error instanceof Error ? error.message : String(error),
59+
stack: error instanceof Error ? error.stack : undefined,
60+
}, 'Failed to complete task');
61+
throw error;
62+
}
2963
}

backend-nodejs/domains/task/handlers/create_task.handler.ts

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,65 @@ import { createContextFromRequest } from '../../../shared/types/context.js';
1313
/**
1414
* CreateTask Handler
1515
* HTTP 适配层:处理创建任务的 HTTP 请求
16+
* 负责日志记录和性能监控,使用 Fastify 的 request.log(自动包含请求上下文)
1617
* 错误由全局错误处理中间件统一处理
1718
*/
1819
export async function createTaskHandler(
1920
deps: HandlerDependencies,
2021
req: FastifyRequest<{ Body: CreateTaskRequest }>,
2122
reply: FastifyReply
2223
): Promise<void> {
23-
// 1. 获取用户 ID(从 JWT Token 中提取)
24+
const startTime = Date.now();
2425
const userId = requireUserId(req);
2526

26-
// 2. 转换为 Domain Input
27-
const input = toCreateTaskInput(userId, req.body);
27+
// 使用 Fastify 的 request.log(自动包含 traceId, requestId)
28+
req.log.info({
29+
userId,
30+
title: req.body.title,
31+
priority: req.body.priority,
32+
hasDueDate: !!req.body.due_date,
33+
tagCount: req.body.tags?.length || 0,
34+
}, 'Creating task');
2835

29-
// 3. 创建请求上下文
30-
const ctx = createContextFromRequest({ userId, ...req });
36+
try {
37+
// 转换为 Domain Input
38+
const input = toCreateTaskInput(userId, req.body);
3139

32-
// 4. 调用 Domain Service(错误会自动向上抛出,由全局错误处理中间件处理)
33-
const output = await deps.taskService.createTask(ctx, input);
40+
// 创建请求上下文
41+
const ctx = createContextFromRequest({ userId, ...req });
3442

35-
// 4. 转换为 HTTP 响应
36-
reply.code(200).send(toCreateTaskResponse(output.task));
43+
// 调用 Domain Service(纯业务逻辑,不包含日志)
44+
const output = await deps.taskService.createTask(ctx, input);
45+
46+
// 记录成功日志和性能指标
47+
const duration = Date.now() - startTime;
48+
req.log.info({
49+
taskId: output.task.id,
50+
userId: output.task.userId,
51+
duration,
52+
}, 'Task created successfully');
53+
54+
// 慢操作警告
55+
if (duration > 1000) {
56+
req.log.warn({
57+
taskId: output.task.id,
58+
duration,
59+
threshold: 1000,
60+
}, 'Slow task creation');
61+
}
62+
63+
// 转换为 HTTP 响应
64+
reply.code(200).send(toCreateTaskResponse(output.task));
65+
} catch (error) {
66+
// 记录错误日志
67+
const duration = Date.now() - startTime;
68+
req.log.error({
69+
userId,
70+
title: req.body.title,
71+
duration,
72+
error: error instanceof Error ? error.message : String(error),
73+
stack: error instanceof Error ? error.stack : undefined,
74+
}, 'Failed to create task');
75+
throw error; // 由全局错误处理器处理
76+
}
3777
}

backend-nodejs/domains/task/handlers/delete_task.handler.ts

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,53 @@ import { createContextFromRequest } from '../../../shared/types/context.js';
1111
/**
1212
* DeleteTask Handler
1313
* HTTP 适配层:处理删除任务的 HTTP 请求
14+
* 负责日志记录和性能监控,使用 Fastify 的 request.log(自动包含请求上下文)
1415
* 错误由全局错误处理中间件统一处理
1516
*/
1617
export async function deleteTaskHandler(
1718
deps: HandlerDependencies,
1819
req: FastifyRequest<{ Params: { id: string } }>,
1920
reply: FastifyReply
2021
): Promise<void> {
22+
const startTime = Date.now();
2123
const userId = requireUserId(req);
2224
const taskId = req.params.id;
2325

24-
const input = toDeleteTaskInput(userId, taskId);
25-
const ctx = createContextFromRequest({ userId, ...req });
26-
const output = await deps.taskService.deleteTask(ctx, input);
26+
req.log.info({
27+
taskId,
28+
userId,
29+
}, 'Deleting task');
2730

28-
reply.code(200).send(toDeleteTaskResponse(output.success, output.deletedAt));
31+
try {
32+
const input = toDeleteTaskInput(userId, taskId);
33+
const ctx = createContextFromRequest({ userId, ...req });
34+
const output = await deps.taskService.deleteTask(ctx, input);
35+
36+
const duration = Date.now() - startTime;
37+
req.log.info({
38+
taskId,
39+
userId,
40+
duration,
41+
}, 'Task deleted successfully');
42+
43+
if (duration > 1000) {
44+
req.log.warn({
45+
taskId,
46+
duration,
47+
threshold: 1000,
48+
}, 'Slow task deletion');
49+
}
50+
51+
reply.code(200).send(toDeleteTaskResponse(output.success, output.deletedAt));
52+
} catch (error) {
53+
const duration = Date.now() - startTime;
54+
req.log.error({
55+
taskId,
56+
userId,
57+
duration,
58+
error: error instanceof Error ? error.message : String(error),
59+
stack: error instanceof Error ? error.stack : undefined,
60+
}, 'Failed to delete task');
61+
throw error;
62+
}
2963
}

backend-nodejs/domains/task/handlers/get_task.handler.ts

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,53 @@ import { createContextFromRequest } from '../../../shared/types/context.js';
1111
/**
1212
* GetTask Handler
1313
* HTTP 适配层:处理获取任务详情的 HTTP 请求
14+
* 负责日志记录和性能监控,使用 Fastify 的 request.log(自动包含请求上下文)
1415
* 错误由全局错误处理中间件统一处理
1516
*/
1617
export async function getTaskHandler(
1718
deps: HandlerDependencies,
1819
req: FastifyRequest<{ Params: { id: string } }>,
1920
reply: FastifyReply
2021
): Promise<void> {
22+
const startTime = Date.now();
2123
const userId = requireUserId(req);
2224
const taskId = req.params.id;
2325

24-
const input = toGetTaskInput(userId, taskId);
25-
const ctx = createContextFromRequest({ userId, ...req });
26-
const output = await deps.taskService.getTask(ctx, input);
26+
req.log.info({
27+
taskId,
28+
userId,
29+
}, 'Getting task');
2730

28-
reply.code(200).send(toGetTaskResponse(output.task));
31+
try {
32+
const input = toGetTaskInput(userId, taskId);
33+
const ctx = createContextFromRequest({ userId, ...req });
34+
const output = await deps.taskService.getTask(ctx, input);
35+
36+
const duration = Date.now() - startTime;
37+
req.log.info({
38+
taskId: output.task.id,
39+
userId: output.task.userId,
40+
duration,
41+
}, 'Task retrieved successfully');
42+
43+
if (duration > 500) {
44+
req.log.warn({
45+
taskId: output.task.id,
46+
duration,
47+
threshold: 500,
48+
}, 'Slow task retrieval');
49+
}
50+
51+
reply.code(200).send(toGetTaskResponse(output.task));
52+
} catch (error) {
53+
const duration = Date.now() - startTime;
54+
req.log.error({
55+
taskId,
56+
userId,
57+
duration,
58+
error: error instanceof Error ? error.message : String(error),
59+
stack: error instanceof Error ? error.stack : undefined,
60+
}, 'Failed to get task');
61+
throw error;
62+
}
2963
}

backend-nodejs/domains/task/handlers/list_tasks.handler.ts

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,66 @@ import { createContextFromRequest } from '../../../shared/types/context.js';
1212
/**
1313
* ListTasks Handler
1414
* HTTP 适配层:处理列出任务的 HTTP 请求
15+
* 负责日志记录和性能监控,使用 Fastify 的 request.log(自动包含请求上下文)
1516
* 错误由全局错误处理中间件统一处理
1617
*/
1718
export async function listTasksHandler(
1819
deps: HandlerDependencies,
1920
req: FastifyRequest<{ Querystring: ListTasksQuery }>,
2021
reply: FastifyReply
2122
): Promise<void> {
23+
const startTime = Date.now();
2224
const userId = requireUserId(req);
2325

24-
const input = toListTasksInput(userId, req.query);
25-
const ctx = createContextFromRequest({ userId, ...req });
26-
const output = await deps.taskService.listTasks(ctx, input);
26+
req.log.info({
27+
userId,
28+
page: req.query.page,
29+
limit: req.query.limit,
30+
status: req.query.status,
31+
priority: req.query.priority,
32+
}, 'Listing tasks');
2733

28-
reply
29-
.code(200)
30-
.send(
31-
toListTasksResponse(
32-
output.tasks,
33-
output.totalCount,
34-
output.page,
35-
output.limit,
36-
output.hasMore
37-
)
38-
);
34+
try {
35+
const input = toListTasksInput(userId, req.query);
36+
const ctx = createContextFromRequest({ userId, ...req });
37+
const output = await deps.taskService.listTasks(ctx, input);
38+
39+
const duration = Date.now() - startTime;
40+
req.log.info({
41+
userId,
42+
taskCount: output.tasks.length,
43+
totalCount: output.totalCount,
44+
duration,
45+
}, 'Tasks listed successfully');
46+
47+
if (duration > 1000) {
48+
req.log.warn({
49+
userId,
50+
taskCount: output.tasks.length,
51+
duration,
52+
threshold: 1000,
53+
}, 'Slow task listing');
54+
}
55+
56+
reply
57+
.code(200)
58+
.send(
59+
toListTasksResponse(
60+
output.tasks,
61+
output.totalCount,
62+
output.page,
63+
output.limit,
64+
output.hasMore
65+
)
66+
);
67+
} catch (error) {
68+
const duration = Date.now() - startTime;
69+
req.log.error({
70+
userId,
71+
duration,
72+
error: error instanceof Error ? error.message : String(error),
73+
stack: error instanceof Error ? error.stack : undefined,
74+
}, 'Failed to list tasks');
75+
throw error;
76+
}
3977
}

backend-nodejs/domains/task/handlers/update_task.handler.ts

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { createContextFromRequest } from '../../../shared/types/context.js';
1515
/**
1616
* UpdateTask Handler
1717
* HTTP 适配层:处理更新任务的 HTTP 请求
18+
* 负责日志记录和性能监控,使用 Fastify 的 request.log(自动包含请求上下文)
1819
* 错误由全局错误处理中间件统一处理
1920
*/
2021
export async function updateTaskHandler(
@@ -25,13 +26,50 @@ export async function updateTaskHandler(
2526
}>,
2627
reply: FastifyReply
2728
): Promise<void> {
28-
// 使用工具函数提取用户 ID 和路径参数
29+
const startTime = Date.now();
2930
const userId = getUserIDFromRequest(req);
3031
const taskId = getRequiredPathParam(req, 'id');
3132

32-
const input = toUpdateTaskInput(userId, taskId, req.body);
33-
const ctx = createContextFromRequest({ userId, ...req });
34-
const output = await deps.taskService.updateTask(ctx, input);
33+
req.log.info({
34+
taskId,
35+
userId,
36+
hasTitle: req.body.title !== undefined,
37+
hasDescription: req.body.description !== undefined,
38+
hasPriority: req.body.priority !== undefined,
39+
hasDueDate: req.body.due_date !== undefined,
40+
hasTags: req.body.tags !== undefined,
41+
}, 'Updating task');
3542

36-
reply.code(200).send(toUpdateTaskResponse(output.task));
43+
try {
44+
const input = toUpdateTaskInput(userId, taskId, req.body);
45+
const ctx = createContextFromRequest({ userId, ...req });
46+
const output = await deps.taskService.updateTask(ctx, input);
47+
48+
const duration = Date.now() - startTime;
49+
req.log.info({
50+
taskId: output.task.id,
51+
userId: output.task.userId,
52+
duration,
53+
}, 'Task updated successfully');
54+
55+
if (duration > 1000) {
56+
req.log.warn({
57+
taskId: output.task.id,
58+
duration,
59+
threshold: 1000,
60+
}, 'Slow task update');
61+
}
62+
63+
reply.code(200).send(toUpdateTaskResponse(output.task));
64+
} catch (error) {
65+
const duration = Date.now() - startTime;
66+
req.log.error({
67+
taskId,
68+
userId,
69+
duration,
70+
error: error instanceof Error ? error.message : String(error),
71+
stack: error instanceof Error ? error.stack : undefined,
72+
}, 'Failed to update task');
73+
throw error;
74+
}
3775
}

0 commit comments

Comments
 (0)