Skip to content

Commit

Permalink
Add log filtering functional
Browse files Browse the repository at this point in the history
Merge pull request #39 from PunGrumpy/feat/filterLogMessage
  • Loading branch information
PunGrumpy authored Apr 9, 2024
2 parents 3c40092 + 94a41ed commit 2a40491
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ app.listen(3000)
| ------------------ | --------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `ip` | `boolean` | Display the incoming IP address based on the `X-Forwarded-For` header | `false` |
| `customLogMessage` | `string` | Custom log message to display | `🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip}` |
| `logFilter` | `object` | Filter the logs based on the level, method, and status | `null` |

## `📄` License

Expand Down
7 changes: 6 additions & 1 deletion example/basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ const app = new Elysia({
config: {
ip: true,
customLogFormat:
'🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip}'
'🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip}',
logFilter: {
level: ['ERROR', 'WARNING'],
status: [500, 404],
method: 'GET'
}
}
})
)
Expand Down
53 changes: 53 additions & 0 deletions src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,55 @@ import {
HttpError
} from './types'

/**
* Filters log messages.
*
* @param {LogLevel} logLevel The log level.
* @param {number} status The status code.
* @param {string} method The method.
* @param {Options} options The options.
* @returns {boolean} `true` if the log message should be logged, otherwise `false`.
*/
function filterLog(
logLevel: LogLevel,
status: number,
method: string,
options?: Options
): boolean {
const filter = options?.config?.logFilter

if (!filter) return true

// Level
if (filter.level) {
if (Array.isArray(filter.level)) {
if (!filter.level.includes(logLevel)) return false
}
} else {
if (filter.level !== logLevel) return false
}

// Status
if (filter.status) {
if (Array.isArray(filter.status)) {
if (!filter.status.includes(status)) return false
}
} else {
if (filter.status !== status) return false
}

// Method
if (filter.method) {
if (Array.isArray(filter.method)) {
if (!filter.method.includes(method)) return false
}
} else {
if (filter.method !== method) return false
}

return true
}

/**
* Logs a message.
*
Expand All @@ -30,6 +79,10 @@ function log(
store: StoreData,
options?: Options
): void {
if (!filterLog(level, data.status || 200, request.method, options)) {
return
}

const logMessage = buildLogMessage(level, request, data, store, options)
console.log(logMessage)
}
Expand Down
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ interface Options {
config?: {
ip?: boolean
customLogFormat?: string
logFilter?: {
level?: LogLevel | LogLevel[]
method?: string | string[]
status?: number | number[]
} | null
}
}

Expand Down
103 changes: 103 additions & 0 deletions test/logixlysia.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,106 @@ describe('Logixlysia with IP logging disabled', () => {
expect(error).toBeInstanceOf(Error)
})
})

describe('Logixlysia with log filtering enabled', () => {
let server: Elysia
let app: any
let logs: string[] = []

beforeAll(() => {
server = new Elysia()
.use(
logger({
config: {
logFilter: {
level: 'INFO',
status: [200, 404],
method: 'GET'
}
}
})
)
.get('/', () => '🦊 Logixlysia Getting')
.post('logixlysia', () => '🦊 Logixlysia Posting')
.listen(3000)

app = edenTreaty<typeof server>('http://127.0.0.1:3000')
})

beforeEach(() => {
logs = []
})

it("Logs 'GET' requests with status 200 or 404 when log filtering criteria are met", async () => {
const requestCount = 5

for (let i = 0; i < requestCount; i++) {
logs.push((await app.get('/')).data)
}

expect(logs.length).toBe(requestCount)
logs.forEach(log => {
expect(log).toMatch('🦊 Logixlysia Getting')
})
})

it("Doesn't log 'POST' requests when log filtering criteria are not met", async () => {
const requestCount = 5

for (let i = 0; i < requestCount; i++) {
await app.post('/logixlysia', {})
}

expect(logs.length).toBe(0)
})

const otherMethods = ['PUT', 'DELETE', 'PATCH', 'HEAD'] // OPTIONS is failed (IDK why)
otherMethods.forEach(async method => {
it(`Logs '${method}' requests with status 200 or 404 when log filtering criteria are met`, async () => {
const requestCount = 5

for (let i = 0; i < requestCount; i++) {
logs.push((await app[method.toLowerCase()]('/')).data)
}

expect(logs.length).toBe(requestCount)
})
})
})

describe('Logixlysia with log filtering disabled', () => {
let server: Elysia
let app: any
let logs: string[] = []

beforeAll(() => {
server = new Elysia()
.use(
logger({
config: {
logFilter: null
}
})
)
.get('/', () => '🦊 Logixlysia Getting')
.post('logixlysia', () => '🦊 Logixlysia Posting')
.listen(3000)

app = edenTreaty<typeof server>('http://127.0.0.1:3000')
})

beforeEach(() => {
logs = []
})

it('Logs all requests when log filtering is disabled', async () => {
const requestCount = 5

for (let i = 0; i < requestCount; i++) {
logs.push((await app.get('/')).data)
logs.push((await app.post('/logixlysia', {})).data)
}

expect(logs.length).toBe(requestCount * 2)
})
})

0 comments on commit 2a40491

Please sign in to comment.