0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-06 20:40:08 -05:00

feat(core): log error body (#1065)

This commit is contained in:
IceHe.xyz 2022-06-07 18:16:14 +08:00 committed by GitHub
parent b2b71898d3
commit 2ba11215ed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 30 deletions

View file

@ -1,5 +1,7 @@
import { LogPayload, LogResult } from '@logto/schemas';
import i18next from 'i18next';
import RequestError from '@/errors/RequestError';
import { insertLog } from '@/queries/log';
import { createContextWithRouteParameters } from '@/utils/test-utils';
@ -21,7 +23,7 @@ jest.mock('nanoid', () => ({
describe('koaLog middleware', () => {
const insertLogMock = insertLog as jest.Mock;
const type = 'SignInUsernamePassword';
const payload: LogPayload = {
const mockPayload: LogPayload = {
userId: 'foo',
username: 'Bar',
};
@ -34,7 +36,7 @@ describe('koaLog middleware', () => {
jest.clearAllMocks();
});
it('insert log with success response', async () => {
it('should insert a success log when next() does not throw an error', async () => {
const ctx: WithLogContext<ReturnType<typeof createContextWithRouteParameters>> = {
...createContextWithRouteParameters({ headers: { 'user-agent': userAgent } }),
// Bypass middleware context type assert
@ -44,7 +46,7 @@ describe('koaLog middleware', () => {
ctx.request.ip = ip;
const next = async () => {
ctx.log(type, payload);
ctx.log(type, mockPayload);
};
await koaLog()(ctx, next);
@ -52,7 +54,7 @@ describe('koaLog middleware', () => {
id: nanoIdMock,
type,
payload: {
...payload,
...mockPayload,
result: LogResult.Success,
ip,
userAgent,
@ -60,7 +62,8 @@ describe('koaLog middleware', () => {
});
});
it('should insert log with failed result if next throws error', async () => {
describe('should insert an error log with the error message when next() throws an error', () => {
it('should log with error message when next throws a normal Error', async () => {
const ctx: WithLogContext<ReturnType<typeof createContextWithRouteParameters>> = {
...createContextWithRouteParameters({ headers: { 'user-agent': userAgent } }),
// Bypass middleware context type assert
@ -69,10 +72,11 @@ describe('koaLog middleware', () => {
};
ctx.request.ip = ip;
const error = new Error('next error');
const message = 'Normal error';
const error = new Error(message);
const next = async () => {
ctx.log(type, payload);
ctx.log(type, mockPayload);
throw error;
};
await expect(koaLog()(ctx, next)).rejects.toMatchError(error);
@ -81,12 +85,47 @@ describe('koaLog middleware', () => {
id: nanoIdMock,
type,
payload: {
...payload,
...mockPayload,
result: LogResult.Error,
error: String(error),
error: { message: `Error: ${message}` },
ip,
userAgent,
},
});
});
it('should insert an error log with the error body when next() throws a RequestError', async () => {
const ctx: WithLogContext<ReturnType<typeof createContextWithRouteParameters>> = {
...createContextWithRouteParameters({ headers: { 'user-agent': userAgent } }),
// Bypass middleware context type assert
addLogContext,
log,
};
ctx.request.ip = ip;
const message = 'Error message';
jest.spyOn(i18next, 't').mockReturnValueOnce(message); // Used in
const code = 'connector.general';
const data = { foo: 'bar', num: 123 };
const error = new RequestError(code, data);
const next = async () => {
ctx.log(type, mockPayload);
throw error;
};
await expect(koaLog()(ctx, next)).rejects.toMatchError(error);
expect(insertLogMock).toBeCalledWith({
id: nanoIdMock,
type,
payload: {
...mockPayload,
result: LogResult.Error,
error: { message, code, data },
ip,
userAgent,
},
});
});
});
});

View file

@ -2,8 +2,10 @@ import { BaseLogPayload, LogPayload, LogPayloads, LogResult, LogType } from '@lo
import deepmerge from 'deepmerge';
import { MiddlewareType } from 'koa';
import { IRouterParamContext } from 'koa-router';
import pick from 'lodash.pick';
import { nanoid } from 'nanoid';
import RequestError from '@/errors/RequestError';
import { insertLog } from '@/queries/log';
type MergeLog = <T extends LogType>(type: T, payload: LogPayloads[T]) => void;
@ -90,7 +92,13 @@ export default function koaLog<
try {
await next();
} catch (error: unknown) {
logger.set({ result: LogResult.Error, error: String(error) });
logger.set({
result: LogResult.Error,
error:
error instanceof RequestError
? pick(error, 'message', 'code', 'data')
: { message: String(error) },
});
throw error;
} finally {
await logger.save();

View file

@ -7,7 +7,7 @@ export enum LogResult {
export interface BaseLogPayload {
result?: LogResult;
error?: string;
error?: Record<string, unknown>;
ip?: string;
userAgent?: string;
applicationId?: string;