@wnqueiroz/ecs-winston
winston logger compatible with Elastic Common Schema (ECS) π
A formatter for the
Table Of Contents
β¨
Key Features - ECS version 1.12 support.
- IntelliSense of ECS fields in writing logs.
- Automatic field conversion when using Express
req
andres
.π - Overwrite and omit the values of the ECS fields that you find necessary.
Install
With NPM:
npm install @wnqueiroz/ecs-winston
Or using Yarn:
yarn add @wnqueiroz/ecs-winston
π‘ Make sure you are using the winston@3.
Usage
Basic Usage
import * as winston from 'winston'
import { ecsWinstonFormat, ECSLog, LogMetadata } from '@wnqueiroz/ecs-winston'
const logger = winston.createLogger({
level: 'info',
format: ecsWinstonFormat(),
transports: [new winston.transports.Console()],
})
const ecs: ECSLog = {
// IntelliSense here π
labels: {
application: 'foo',
},
tags: ['api'],
}
const log: LogMetadata = {
ecs,
}
logger.info(log)
logger.info('This is amazing!!', log)
# logger.info(log)
{"@timestamp":"2021-10-08T20:56:37.643Z","labels":{"application":"foo"},"message":"","tags":["api"],"log":{"level":"info"},"ecs":{"version":"1.12.0"}}
# logger.info('This is amazing!!', log)
{"@timestamp":"2021-10-08T20:56:37.649Z","labels":{"application":"foo"},"message":"This is amazing!!","tags":["api"],"log":{"level":"info"},"ecs":{"version":"1.12.0"}}
req
and res
Converting Express Let's configure a simple express application that, when finalizing a HTTP Request, an access log will be created:
import { ecsWinstonFormat, LogMetadata } from '@wnqueiroz/ecs-winston'
import * as winston from 'winston'
import express, { Request, Response } from 'express'
const app = express()
const logger = winston.createLogger({
level: 'info',
format: ecsWinstonFormat(),
transports: [new winston.transports.Console()],
})
app.get('/', (req: Request, res: Response) => {
const payload = {
data: 'foo',
}
res.locals.body = payload // will be injected into http.response.body.content
req.on('end', () => {
const log: LogMetadata = {
req,
res,
}
logger.info('access log', log)
})
res.json(payload)
})
const port = 3000
app.listen(port, () => {
logger.info(`app listening at http://localhost:${port}`)
})
When making the HTTP Request GET http://localhost:3000
, the log displayed will look something like:
{
"@timestamp": "2021-10-09T20:31:08.828Z",
"message": "access log",
"log": {
"level": "info"
},
"ecs": {
"version": "1.12.0"
},
"http": {
"version": "1.1",
"request": {
"id": "",
"method": "GET",
"headers": {
"user-agent": "Thunder Client (https://www.thunderclient.io)",
"accept": "*/*",
"accept-encoding": "gzip, deflate, br",
"host": "localhost:3000",
"connection": "close"
},
"body": {}
},
"response": {
"status_code": 200,
"mime_type": "application/json; charset=utf-8",
"body": {
"bytes": 14,
"content": {
"data": "foo"
}
}
}
},
"user_agent": {
"original": "Thunder Client (https://www.thunderclient.io)"
}
}
Removing ECS fields from the log
It's possible to configure the formatter to exclude ECS properties by default (from all written logs):
import { ecsWinstonFormat, LogMetadata } from '@wnqueiroz/ecs-winston'
import * as winston from 'winston'
const logger = winston.createLogger({
level: 'info',
format: ecsWinstonFormat({
exclude: ['http.request.headers.authorization'], // will remove this property from all logs by default.
}),
transports: [new winston.transports.Console()],
})
Or delete the property from that log only:
const log: LogMetadata = {
ecs: {
message: 'exclude example',
labels: {
application: 'foo', // will be removed
foo: 'bar',
},
},
exclude: ['labels.application'],
}
logger.info(log)
// {"@timestamp":"2021-10-11T14:40:35.163Z","labels":{"foo":"bar"},"message":"exclude example","log":{"level":"info"},"ecs":{"version":"1.12.0"}}
π‘ It is possible to combine the two strategies: excluding properties by default (at configuration) and from a specific log.
π§
Roadmap - Integration with Elastic APM.
License
This software is licensed under the MIT license.