Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabled colorization #42

Merged
merged 18 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ const server = fastify({
});
```

## Colors

Colors are enabled by default when supported. To manually disable the colors you need to set the `transport.colorize` option to `false`. For more options check the `colorette` [docs](https://github.com/jorgebucaran/colorette?tab=readme-ov-file#environment).

```js
const server = fastify({
logger: {
transport: {
target: "@fastify/one-line-logger",
colorize: false,
},
},
});
```


## Custom levels

Custom levels could be used by passing it into logger opts
Expand Down
8 changes: 6 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ const pretty = require('pino-pretty')
const messageFormatFactory = require('./lib/messageFormatFactory')

const oneLineLogger = (opts = {}) => {
const { colorize, levels, colors, ...rest } = opts
const { levels, colors, ...rest } = opts

const messageFormat = messageFormatFactory(colorize, levels, colors)
const messageFormat = messageFormatFactory(
levels,
colors,
opts.colorize ?? pretty.isColorSupported
)

return pretty({
messageFormat,
Expand Down
25 changes: 15 additions & 10 deletions lib/messageFormatFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
const formatDate = require('./formatDate')
const colorizerFactory = require('pino-pretty').colorizerFactory

const messageFormatFactory = (colorize, levels, colors) => {
const customColors = colors != null
? Object.entries(colors).reduce((colors, [level, color]) => {
return [...colors, [level, color]]
}, [])
: undefined
const colorizer = colorizerFactory(colorize === true, customColors)
const messageFormatFactory = (levels, colors, useColors) => {
const customColors =
colors != null
? Object.entries(colors).reduce((colors, [level, color]) => {
return [...colors, [level, color]]
}, [])
: undefined
const colorizer = colorizerFactory(useColors, customColors)

const levelLookUp = {
60: colorizer('fatal').toLowerCase(),
Expand All @@ -24,18 +25,22 @@ const messageFormatFactory = (colorize, levels, colors) => {
Object.entries(levels).forEach(([name, level]) => {
const customLevels = { [level]: name }
const customLevelNames = { [name]: level }
levelLookUp[level] = colorizer(name, { customLevelNames, customLevels }).toLowerCase()
levelLookUp[level] = colorizer(name, {
customLevelNames,
customLevels
}).toLowerCase()
})
}

const colorizeMessage = colorizer.message

const messageFormat = (log, messageKey) => {
const time = formatDate(log.time)
const level = levelLookUp[log.level]

return log.req
? `${time} - ${level} - ${log.req.method} ${log.req.url} - ${colorizeMessage(log[messageKey])}`
? `${time} - ${level} - ${log.req.method} ${
log.req.url
} - ${colorizeMessage(log[messageKey])}`
: `${time} - ${level} - ${colorizeMessage(log[messageKey])}`
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"test": "test"
},
"dependencies": {
"pino-pretty": "^11.0.0"
"pino-pretty": "^11.1.0"
},
"devDependencies": {
"benchmark": "^2.1.4",
Expand Down
158 changes: 110 additions & 48 deletions test/fastify.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'

const { serverFactory, TIME, unmockTime, mockTime } = require('./helpers')
const pretty = require('pino-pretty')
const tap = require('tap')

const { test } = tap
Expand All @@ -24,69 +25,130 @@ tap.beforeEach(() => {
})

test('should log server started messages', async (t) => {
await server.listen({ port: 63995 })
t.beforeEach(async () => {
await server.listen({ port: 63995 })
t.teardown(async () => await server.close())
})

t.test('colors supported in TTY', { skip: !pretty.isColorSupported }, (t) => {
const messagesExpected = [
`${TIME} - \x1B[32minfo\x1B[39m - \x1B[36mServer listening at http://127.0.0.1:63995\x1B[39m\n`,
`${TIME} - \x1B[32minfo\x1B[39m - \x1B[36mServer listening at http://[::1]:63995\x1B[39m\n`
]

const messagesExpected = [
`${TIME} - info - Server listening at http://127.0.0.1:63995\n`,
`${TIME} - info - Server listening at http://[::1]:63995\n`
]
// sort because the order of the messages is not guaranteed
t.same(messages.sort(), messagesExpected.sort())
t.end()
})

// sort because the order of the messages is not guaranteed
t.same(messages.sort(), messagesExpected.sort())
await server.close()
t.end()
t.test(
'colors not supported in TTY',
{ skip: pretty.isColorSupported },
(t) => {
const messagesExpected = [
`${TIME} - info - Server listening at http://127.0.0.1:63995\n`,
`${TIME} - info - Server listening at http://[::1]:63995\n`
]

// sort because the order of the messages is not guaranteed
t.same(messages.sort(), messagesExpected.sort())
t.end()
}
)
})

const methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD']
methods.forEach((method) => {
test('should log request and response messages for %p', async (t) => {
const serverMethod = method === 'HEAD' ? 'GET' : method
server[serverMethod.toLowerCase()]('/path', (_, req) => {
req.send()
})

await server.inject({
method,
url: '/path'
t.beforeEach(async () => {
const serverMethod = method === 'HEAD' ? 'GET' : method
server[serverMethod.toLowerCase()]('/path', (_, req) => {
req.send()
})

await server.inject({
method,
url: '/path'
})
})

const messagesExpected = [
`${TIME} - info - ${method} /path - incoming request\n`,
`${TIME} - info - request completed\n`
]

t.same(messages, messagesExpected)
t.end()
t.test(
'colors supported in TTY',
{ skip: !pretty.isColorSupported },
(t) => {
const messagesExpected = [
`${TIME} - \x1B[32minfo\x1B[39m - ${method} /path - \x1B[36mincoming request\x1B[39m\n`,
`${TIME} - \x1B[32minfo\x1B[39m - \x1B[36mrequest completed\x1B[39m\n`
]
t.same(messages, messagesExpected)
t.end()
}
)

t.test(
'colors not supported in TTY',
{ skip: pretty.isColorSupported },
(t) => {
const messagesExpected = [
`${TIME} - info - ${method} /path - incoming request\n`,
`${TIME} - info - request completed\n`
]
t.same(messages, messagesExpected)
t.end()
}
)
})
})

test('should handle user defined log', async (t) => {
server = serverFactory(messages, { minimumLevel: 'trace' })
t.beforeEach(async () => {
server = serverFactory(messages, { minimumLevel: 'trace' })

server.get('/a-path-with-user-defined-log', (res, req) => {
res.log.fatal('a user defined fatal log')
res.log.error('a user defined error log')
res.log.warn('a user defined warn log')
res.log.info('a user defined info log')
res.log.debug('a user defined debug log')
res.log.trace('a user defined trace log')

server.get('/a-path-with-user-defined-log', (res, req) => {
res.log.fatal('a user defined fatal log')
res.log.error('a user defined error log')
res.log.warn('a user defined warn log')
res.log.info('a user defined info log')
res.log.debug('a user defined debug log')
res.log.trace('a user defined trace log')
req.send()
})

req.send()
await server.inject('/a-path-with-user-defined-log')
})

t.test('colors supported in TTY', { skip: !pretty.isColorSupported }, (t) => {
const messagesExpected = [
`${TIME} - \x1B[32minfo\x1B[39m - GET /a-path-with-user-defined-log - \x1B[36mincoming request\x1B[39m\n`,
`${TIME} - \x1B[41mfatal\x1B[49m - \x1B[36ma user defined fatal log\x1B[39m\n`,
`${TIME} - \x1B[31merror\x1B[39m - \x1B[36ma user defined error log\x1B[39m\n`,
`${TIME} - \x1B[33mwarn\x1B[39m - \x1B[36ma user defined warn log\x1B[39m\n`,
`${TIME} - \x1B[32minfo\x1B[39m - \x1B[36ma user defined info log\x1B[39m\n`,
`${TIME} - \x1B[34mdebug\x1B[39m - \x1B[36ma user defined debug log\x1B[39m\n`,
`${TIME} - \x1B[90mtrace\x1B[39m - \x1B[36ma user defined trace log\x1B[39m\n`,
`${TIME} - \x1B[32minfo\x1B[39m - \x1B[36mrequest completed\x1B[39m\n`
]
t.same(messages, messagesExpected)
t.end()
})

await server.inject('/a-path-with-user-defined-log')

const messagesExpected = [
`${TIME} - info - GET /a-path-with-user-defined-log - incoming request\n`,
`${TIME} - fatal - a user defined fatal log\n`,
`${TIME} - error - a user defined error log\n`,
`${TIME} - warn - a user defined warn log\n`,
`${TIME} - info - a user defined info log\n`,
`${TIME} - debug - a user defined debug log\n`,
`${TIME} - trace - a user defined trace log\n`,
`${TIME} - info - request completed\n`
]

t.same(messages, messagesExpected)
t.end()
t.test(
'colors not supported in TTY',
{ skip: pretty.isColorSupported },
(t) => {
const messagesExpected = [
`${TIME} - info - GET /a-path-with-user-defined-log - incoming request\n`,
`${TIME} - fatal - a user defined fatal log\n`,
`${TIME} - error - a user defined error log\n`,
`${TIME} - warn - a user defined warn log\n`,
`${TIME} - info - a user defined info log\n`,
`${TIME} - debug - a user defined debug log\n`,
`${TIME} - trace - a user defined trace log\n`,
`${TIME} - info - request completed\n`
]
t.same(messages, messagesExpected)
t.end()
}
)
})
5 changes: 2 additions & 3 deletions test/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ const pinoFactory = (opts) => {
return pino(
{ level },
target({
colorize: false,
...opts
})
)
Expand Down Expand Up @@ -57,9 +56,9 @@ const mockTime = () => {
const unmockTime = () => {
Date.now = dateOriginalNow
// eslint-disable-next-line
Date.prototype.getTimezoneOffset = dateGetTimezoneOffset
Date.prototype.getTimezoneOffset = dateGetTimezoneOffset;
// eslint-disable-next-line
Date.prototype.getHours = dateOriginalGetHours
Date.prototype.getHours = dateOriginalGetHours;
}

module.exports = {
Expand Down
Loading
Loading