@recombine-ai/dockyard
v0.2.0
Published
**Usage:**
Readme
The Dockyard
Logger
Usage:
import createLogger from '@recombine-ai/dockyard/logger'
const logger = createLogger({
level: 'debug',
mode: 'production',
addTimestamp: true,
addStackTrace: true,
redactedFields: ['password', 'phone', 'user.data'],
globalFields: { app: 'this' },
})
logger.setGlobalId('callId')
logger.info('It works', { foo: 'bar' })
logger.log('It works too', 42)
logger.debug('Spam', ['eggs'])
logger.info('Secret', { password: 'p@sswd', user: { data: 'personal' } })
logger.error('Oh no', { err: new Error('Panic') })In Fastify app routes:
import { loggerContext } from '@recombine-ai/dockyard/logger'
// ... Create Fastify app
// 1. Register once, before routes — covers ALL requests:
app.addHook('onRequest', async () => {
await loggerContext.enterWith()
})
// 2. Add preHandler:
app.addHook('preHandler', async (req, res) => {
req.callId = req.headers['x-call-id']
})
// 3. In initial route:
app.all('/', async (req, res) => {
loggerContext.setLocal({ [LOG_RECORD_GLOBAL_ID_KEY]: req.callId })
})Example logs:
{
"level": "INFO",
"time": "2025-10-27T23:26:48.624Z",
"ctx": {
"foo": "bar"
},
"app": "this",
"room": "callId",
"msg": "It works"
}
{
"level": "INFO",
"time": "2025-10-27T23:26:48.624Z",
"ctx": {
"val": 42
},
"app": "this",
"room": "callId",
"msg": "It works too"
}
{
"level": "DEBUG",
"time": "2025-10-27T23:26:48.624Z",
"ctx": {
"enum": [
"eggs"
]
},
"app": "this",
"room": "callId",
"msg": "Spam"
}
{
"level": "INFO",
"time": "2025-10-27T23:26:48.624Z",
"ctx": {
"password": "***",
"user": {
"data": "***"
}
},
"app": "this",
"room": "callId",
"msg": "Secret"
}
{
"level": "ERROR",
"time": "2025-10-27T23:26:48.624Z",
"err": {
"type": "Error",
"message": "Panic"
},
"app": "this",
"room": "callId",
"msg": "Oh no"
}