https://github.com/zenvia/zenvia-logger-node
A wrapper for Winston Logging Node.js library that formats the output on STDOUT as Logstash JSON format.
https://github.com/zenvia/zenvia-logger-node
hacktoberfest logger logstash winston zenvia
Last synced: 4 days ago
JSON representation
A wrapper for Winston Logging Node.js library that formats the output on STDOUT as Logstash JSON format.
- Host: GitHub
- URL: https://github.com/zenvia/zenvia-logger-node
- Owner: zenvia
- License: mit
- Created: 2019-03-06T23:22:35.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2024-06-16T13:10:23.000Z (over 1 year ago)
- Last Synced: 2025-04-10T00:53:15.051Z (9 months ago)
- Topics: hacktoberfest, logger, logstash, winston, zenvia
- Language: JavaScript
- Homepage:
- Size: 368 KB
- Stars: 5
- Watchers: 23
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# Zenvia Logger for Node.js
A wrapper for [Winston](https://github.com/winstonjs/winston) Logging [Node.js](https://nodejs.org/) library that formats the output on STDOUT as [Logstash](https://www.elastic.co/logstash) JSON format.
**Main features:**
- **Dual Package Support:** Native support for both **ES Modules (ESM)** and **CommonJS (CJS)**.
- **Node 24 Ready:** Optimized for native TypeScript execution (Type Stripping).
- **Distributed Tracing:** Automated request tracking using [cls-rtracer](https://www.npmjs.com/package/cls-rtracer).
[](LICENSE.md)
[](https://travis-ci.com/zenvia/zenvia-logger-node)
[](https://coveralls.io/github/zenvia/zenvia-logger-node?branch=master)
[](https://david-dm.org/zenvia/zenvia-logger-node)
[](https://twitter.com/intent/follow?screen_name=ZENVIA_)
## Installation
```bash
npm install @zenvia/logger
```
## Environment Variables
The following environment variables can be used for increase the log information:
- **APP_NAME**: value to filled the "application" field in the output JSON. If empty, the **name** attribute on `package.json` will be used instead.
- **NODE_ENV**: value to filled the "environment" field in the output JSON.
- **HOST** or **HOSTNAME**: value to filled the "host" field in the output JSON.
- **LOGGING_LEVEL**: set the level of messages that the logger should log. Default to `DEBUG`.
- **LOGGING_FORMATTER_DISABLED** *(version 1.1.0 and above)*: When `true`, the output logging will not be formatted to JSON. Useful during development time. Default to `false`.
- **LOGGING_FRAMEWORK_MIDDLEWARE** *(version 1.5.0 and above)*: Value that defines which middleware will be used. It is possible to choose between the middlewares: EXPRESS, FASTIFY, HAPI and KOA. If empty, the middleware default is `EXPRESS`.
- **LOGGING_TRACE_HEADER** *(version 1.5.0 and above)*: Value indicating the header name that must be obtained from the traceId value in the request. Default is `X-TraceId`.
## Basic Usage (Express users)
```js
// ES6 or Typescript
import express from 'express';
import logger, { traceMiddleware } from '@zenvia/logger';
const app = express();
app.use(traceMiddleware);
logger.info('some message');
```
## Basic Usage (FASTIFY users)
```js
// ES6 or Typescript
import fastify from 'fastify'
import logger, { traceMiddleware } from '@zenvia/logger';
fastify.register(traceMiddleware);
logger.info('some message');
```
## Basic Usage (KOA users)
```js
// ES6 or Typescript
import Koa from 'koa';
import logger, { traceMiddleware } from '@zenvia/logger';
const app = new Koa();
app.use(traceMiddleware);
logger.info('some message');
```
## Basic Usage (HAPI users)
```js
// ES6 or Typescript
import Koa from 'koa';
import logger, { traceMiddleware } from '@zenvia/logger';
const init = async () => {
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
await server.register({
plugin: traceMiddleware
});
}
logger.info('some message');
```
Output:
```bash
{
"@timestamp": "2018-06-05T18:20:42.345Z",
"@version": 1,
"application": "application-name",
"message": "some message",
"level": "INFO",
"traceID": "123e4567-e32b-12d3-a432-626614174888"
}
```
## Available logging levels
The log levels are as follows.
- **fatal**
- **error**
- **warn**
- **info**
- **debug**
For backward compatibility purposes, **"verbose"** and **"silly"** levels will behave the same as "debug" level.
## Adding extra key/value fields
```js
logger.debug('Some text message', { keyA: 'value A', keyB: 'value B' });
```
Output:
```bash
{
"keyA": "value A",
"keyB": "value B",
"@timestamp": "2018-06-05T22:04:42.039Z",
"@version": 1,
"application": "application-name",
"message": "Some text message",
"level": "DEBUG"
}
```
## Logging errors
```js
logger.error('Ops!', new Error('Something goes wrong'));
```
Output:
```bash
{
"message": "Ops!: Something goes wrong",
"@timestamp": "2018-06-05T22:14:09.683Z",
"@version": 1,
"application": "application-name",
"level": "ERROR",
"stack_trace": "Error: Something goes wrong\n at repl:1:34\n at Script.runInThisContext (vm.js:91:20)\n at REPLServer.defaultEval (repl.js:317:29)\n at bound (domain.js:396:14)\n at REPLServer.runBound [as eval] (domain.js:409:12)\n at REPLServer.onLine (repl.js:615:10)\n at REPLServer.emit (events.js:187:15)\n at REPLServer.EventEmitter.emit (domain.js:442:20)\n at REPLServer.Interface._onLine (readline.js:290:10)\n at REPLServer.Interface._line (readline.js:638:8)"
}
```
Due to limitations of winston lib, when a text, an error and extra key/value fields are logged at once, the output message field will contain the text message, the error message and the full stack trace as shown.
```js
logger.fatal('Ops!', { new Error('Something goes wrong'), { keyA: 'value A', keyB: 'value B' } });
```
Output:
```bash
{
"keyA": "value A",
"keyB": "value B",
"@timestamp": "2018-06-05T22:09:22.750Z",
"@version": 1,
"application": "application-name",
"message": "Ops! Error: Something goes wrong\n at repl:1:34\n at Script.runInThisContext (vm.js:91:20)\n at REPLServer.defaultEval (repl.js:317:29)\n at bound (domain.js:396:14)\n at REPLServer.runBound [as eval] (domain.js:409:12)\n at REPLServer.onLine (repl.js:615:10)\n at REPLServer.emit (events.js:187:15)\n at REPLServer.EventEmitter.emit (domain.js:442:20)\n at REPLServer.Interface._onLine (readline.js:290:10)\n at REPLServer.Interface._line (readline.js:638:8)",
"level": "FATAL"
}
```
## Using trace logs
From version 1.5.0 it is possible to track logs. To do traceability, the cls-rTrace package is used. To use it, just add the middleware in the framework you are using. In this way it is possible to propagate the traceId received in a request to the logs throughout your project. If no traceId is passed in the request, Zenvia Logger generates a random traceId for the request being processed.
**Request example sending traceId:**
```bash
curl 'http://localhost/your-application' \
--header 'X-TraceId: dbcdd40e-10cd-40a7-b912-1b0a17483d67' \
```
Log
```javascript
logger.info('message with traceID');
```
Log Output
```json
{
"@timestamp": "2018-06-05T18:20:42.345Z",
"@version": 1,
"application": "application-name",
"message": "message with traceID",
"level": "INFO",
"traceID": "dbcdd40e-10cd-40a7-b912-1b0a17483d67'"
}
```
**Request example without sending traceId:**
```bash
curl 'http://localhost/your-application'
```
Log
```javascript
logger.info('message without traceID');
```
Log Output
```json
{
"@timestamp": "2018-06-05T18:20:42.345Z",
"@version": 1,
"application": "application-name",
"message": "message with traceID",
"level": "INFO",
"traceID": "912c029c-c38f-49e7-9968-e575c5108178'"
}
```
## Contextual Logging (Async Context)
You can use `runWithContext` and `addContext` to manage metadata context across asynchronous flows (like Kafka consumers or complex background jobs). This ensures all logs within a specific execution thread share the same context without passing a logger instance manually.
### Basic Usage with runWithContext
Useful for isolating logs from different event sources or partitions.
```js
import logger from '@zenvia/logger';
async function handleEvent(event) {
await logger.runWithContext({
partition: event.partition,
topic: 'orders-topic'
}, async () => {
// All logs here will include partition and topic automatically
logger.info('Processing started');
await processOrder(event.data);
});
}
```
### Enriching Context with addContext
You can inject new metadata into the current context at any point during the execution.
```js
import logger from '@zenvia/logger';
async function processOrder(data) {
logger.info('Validating...');
const provider = await api.getProvider(data.id);
// Mutates the current context to include providerId in all subsequent logs
logger.addContext({ providerId: provider.id });
logger.info('Validation complete');
// Output JSON will contain: partition, topic AND providerId
}
```
### Nested Contexts
Contexts can be nested. The inner context will inherit metadata from the parent.
```js
await logger.runWithContext({ level1: 'A' }, async () => {
await logger.runWithContext({ level2: 'B' }, async () => {
logger.info('Log with A and B');
});
});
```
## License
[MIT](LICENSE.md)