
Research
/Security News
Malicious npm Packages Target WhatsApp Developers with Remote Kill Switch
Two npm packages masquerading as WhatsApp developer libraries include a kill switch that deletes all files if the phone number isn’t whitelisted.
pino-lambda
Advanced tools
pino-lambda is a logging library designed to integrate the Pino logger with AWS Lambda functions. It provides a streamlined way to handle logging in serverless environments, ensuring that logs are formatted and managed efficiently.
Integration with AWS Lambda
This feature allows you to wrap your AWS Lambda handler with pino-lambda, enabling structured logging using Pino within the Lambda environment. The code sample demonstrates how to use pino-lambda to log an informational message within a Lambda function.
const pinoLambda = require('pino-lambda');
exports.handler = pinoLambda((event, context) => {
context.log.info('This is an info log');
return {
statusCode: 200,
body: JSON.stringify({ message: 'Hello from Lambda!' })
};
});
Custom Log Levels
pino-lambda supports various log levels such as info, warn, and error. This feature allows developers to log messages at different severity levels, which can be useful for debugging and monitoring. The code sample shows how to log warning and error messages.
const pinoLambda = require('pino-lambda');
exports.handler = pinoLambda((event, context) => {
context.log.warn('This is a warning log');
context.log.error('This is an error log');
return {
statusCode: 200,
body: JSON.stringify({ message: 'Check the logs for warnings and errors' })
};
});
Winston is a versatile logging library for Node.js that supports multiple transports and log levels. While it is not specifically designed for AWS Lambda, it can be configured to work in serverless environments. Compared to pino-lambda, Winston offers more flexibility in terms of transport options and log formatting.
Bunyan is another logging library for Node.js that provides a simple and fast JSON logging solution. Like Pino, it is designed for high performance and can be used in AWS Lambda with some configuration. Bunyan is similar to pino-lambda in its focus on JSON logging but does not offer the same out-of-the-box integration with AWS Lambda.
Log4js is a logging library inspired by Log4j for Java. It supports various appenders and log levels, making it a flexible choice for Node.js applications. While it can be used in AWS Lambda, it requires more setup compared to pino-lambda, which is specifically tailored for Lambda environments.
A custom destination for pino that takes advantage of the unique environment in AWS Lambda functions. ref
By default, this destination reformats the log output so it matches the existing Cloudwatch format. The default pino log format loses some of the built in support for request ID tracing that lambda has built into to support Cloudwatch insights and Xray tracing.
It also automatically tracks the request id, correlation ids, and xray tracing from upstream services.
Basic usage for most applications
import pino from 'pino';
import { lambdaRequestTracker, pinoLambdaDestination } from 'pino-lambda';
// custom destination formatter
const destination = pinoLambdaDestination();
const logger = pino(
{
// typical pino options
},
destination,
);
const withRequest = lambdaRequestTracker();
async function handler(event, context) {
// automatic request tracing across all instances of pino
// called once at the beginning of your Lambda handler
withRequest(event, context);
// typical logging methods
logger.info({ data: 'Some data' }, 'A log message');
}
Cloudwatch output will now match the native console.log
output, correctly preserving
@requestid
, @timestamp
, and @message
properties for use in Cloudwatch Insights and
other Cloudwatch aware tools such as Datadog and Splunk.
2018-12-20T17:05:25.330Z 6fccb00e-0479-11e9-af91-d7ab5c8fe19e INFO A log message
{
"awsRequestId": "6fccb00e-0479-11e9-af91-d7ab5c8fe19e",
"x-correlation-id": "238da608-0542-11e9-8eb2-f2801f1b9fd1",
"x-correlation-trace-id": "Root=1-5c1bcbd2-9cce3b07143efd5bea1224f2;Parent=07adc05e4e92bf13;Sampled=1",
"level": 30,
"message": "A log message",
"data": "Some data"
}
The request logging context can be updated downstream by calling the updateContext
function. Any duplicate values will overwrite previous values.
Note: If you provide a custom storage context, you will need to update that storage context directly (this is not typical)
import { GlobalContextStorageProvider } from 'pino-lambda';
GlobalContextStorageProvider.updateContext({ userId: '12' });
With context tracing enabled, all instances of pino
that use one of the built in formatters will automatically log the request id and other details so you don't need to pass an instance of a logger to all of your functions.
Property | Value | Info |
---|---|---|
awsRequestId | context.awsRequestId | The unique request id for this request |
apiRequestId | context.requestContext.requestId | The API Gateway RequestId |
x-correlation-id | event.headers['x-correlation-id'] | The upstream request id for tracing |
x-correlation-trace-id | process.env._X_AMZN_TRACE_ID | The AWS Xray tracking id |
x-correlation-* | event.headers.startsWith('x-correlation-') | Any header that starts with x-correlation- will be automatically added |
Every AWS Lambda request contains a unique request ID, context.awsRequestId
. If the request originated outside of the AWS platform,
the request ID will match the event.header.x-correlation-id
value. However, if the request originated from within the AWS platform,
the event.header.x-correlation-id
will be set to the request ID of the calling service. This allows you to trace a request
across the entire platform.
Amazon XRAY also has a unique tracing ID that is propagated across the requests and can be tracked as well.
You can customize the data that is tracked for each request by adding a per-request mixin.
The request mixin takes the Lambda event
and context
and returns an object.
This differs from the built in pino mixin as it only executes once per request where the built in pino mixin runs once per log entry.
import pino from 'pino';
import { lambdaRequestTracker, pinoLambdaDestination } from 'pino-lambda';
const destination = pinoLambdaDestination();
const logger = pino(destination);
const withRequest = lambdaRequestTracker({
requestMixin: (event, context) => {
return {
// add request header host name
host: event.headers?.host,
// you can also set any request property to undefined
// which will remove it from the output
'x-correlation-id': undefined,
// add any type of static data
brand: 'famicom',
};
},
});
async function handler(event, context) {
withRequest(event, context);
logger.info({ data: 'Some data' }, 'A log message');
}
Output
2018-12-20T17:05:25.330Z 6fccb00e-0479-11e9-af91-d7ab5c8fe19e INFO A log message
{
"awsRequestId": "6fccb00e-0479-11e9-af91-d7ab5c8fe19e",
"x-correlation-trace-id": "Root=1-5c1bcbd2-9cce3b07143efd5bea1224f2;Parent=07adc05e4e92bf13;Sampled=1",
"level": 30,
"host": "www.host.com",
"brand": "famicom",
"message": "A log message",
"data": "Some data"
}
By default, the pinoLambdaDestination
uses the CloudwatchLogFormatter
.
If you would like to use the new AWS Lambda Advanced Logging Controls format for your logs, ensure your Lambda function is properly configured and enable StructuredLogFormatter
in pino-lambda
.
import pino from 'pino';
import { lambdaRequestTracker, pinoLambdaDestination, StructuredLogFormatter } from 'pino-lambda';
const destination = pinoLambdaDestination({
formatter: new StructuredLogFormatter()
});
const logger = pino(destination);
const withRequest = lambdaRequestTracker();
async function handler(event, context) {
withRequest(event, context);
logger.info({ data: 'Some data' }, 'A log message');
}
Output
{
"timestamp": "2016-12-01T06:00:00.000Z",
"requestId": "6fccb00e-0479-11e9-af91-d7ab5c8fe19e",
"level": "INFO",
"message": {
"msg": "A log message",
"data": "Some data",
"x-correlation-trace-id": "Root=1-5c1bcbd2-9cce3b07143efd5bea1224f2;Parent=07adc05e4e92bf13;Sampled=1"
}
}
If you want the request tracing features of pino-lambda
, but don't need the Cloudwatch format, you can use the PinoLogFormatter
which matches the default object output format of pino
.
import pino from 'pino';
import { lambdaRequestTracker, pinoLambdaDestination, PinoLogFormatter } from 'pino-lambda';
const destination = pinoLambdaDestination({
formatter: new PinoLogFormatter(),
});
const logger = pino(destination);
const withRequest = lambdaRequestTracker();
async function handler(event, context) {
withRequest(event, context);
logger.info({ data: 'Some data' }, 'A log message');
}
Output
{
"awsRequestId": "6fccb00e-0479-11e9-af91-d7ab5c8fe19e",
"x-correlation-trace-id": "Root=1-5c1bcbd2-9cce3b07143efd5bea1224f2;Parent=07adc05e4e92bf13;Sampled=1",
"level": 30,
"time": 1480572000000,
"msg": "A log message",
"data": "Some data"
}
The formatter function can also be replaced with any custom implementation you need by using the supplied interface.
import { LogData, ILogFormatter } from 'pino-lambda';
class BananaLogFormatter implements ILogFormatter {
format(data: LogData) {
return `[BANANA] ${JSON.stringify(data)}`;
}
}
const destination = pinoLambdaDestination({
formatter: new BananaLogFormatter(),
});
const logger = pino(destination);
Output
[BANANA]
{
"awsRequestId": "6fccb00e-0479-11e9-af91-d7ab5c8fe19e",
"x-correlation-trace-id": "Root=1-5c1bcbd2-9cce3b07143efd5bea1224f2;Parent=07adc05e4e92bf13;Sampled=1",
"level": 30,
"msg": "A log message",
"data": "Some data"
}
Unless your application is small, it can be useful to split the logger into its own module for easier reuse across your application code. This ensures that all your logging calls receive the correct formatting and context across the request.
// logger.ts
import pino from 'pino';
import { pinoLambdaDestination } from 'pino-lambda';
const destination = pinoLambdaDestination();
export const logger = pino(destination);
// handler.ts
import { lambdaRequestTracker } from 'pino-lambda';
import { logger } from './logger';
const withRequest = lambdaRequestTracker();
async function handler(event, context) {
// automatic request tracing across all instances of pino
// called once at the beginning of your Lambda handler
withRequest(event, context);
// typical logging methods
logger.info({ data: 'Some data' }, 'A log message');
}
You can use the this wrapper outside of the AWS lambda function in any place you want. This is especially useful in private npm modules that will be used by your AWS Lambda function. The default logger context is a shared instance, so it inherits all properties the default is configured for, and will emit request information for all logs. This effectively allows you to track a request across its entire set of log entries.
Please see our contributing guide.
Active: Formidable is actively working on this project, and we expect to continue for work for the foreseeable future. Bug reports, feature requests and pull requests are welcome.
FAQs
Pino destination formatter for AWS Lambda
The npm package pino-lambda receives a total of 147,353 weekly downloads. As such, pino-lambda popularity was classified as popular.
We found that pino-lambda demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
Two npm packages masquerading as WhatsApp developer libraries include a kill switch that deletes all files if the phone number isn’t whitelisted.
Research
/Security News
Socket uncovered 11 malicious Go packages using obfuscated loaders to fetch and execute second-stage payloads via C2 domains.
Security News
TC39 advances 11 JavaScript proposals, with two moving to Stage 4, bringing better math, binary APIs, and more features one step closer to the ECMAScript spec.