Middy: Modifying/extending/injecting into event or context

Created on 13 Apr 2020  路  7Comments  路  Source: middyjs/middy

I'm wanting to provide standardised/shareable logging for my Lambda functions and after reading this article on Decorated Lambda handlers I wondered if Middy would offer a solution.

I thought about for this a bit and then started to have some doubts. Middy would clearly provide a great solution if I wanted to do some standardised logging _around_ each Lambda invocation, but what I really want to do is provide a logger object that is available to Lambda's that would use my middleware.

I scanned the documentation and looked at the implementation of some middlewares and I couldn't find a clear pattern for this or even be sure if this was endorsed. Looking through opened and closed issues I still came away unsure. Based on that I thought I'd raise the issue to ask.

Essentially I want to write a middleware that supports New Relic logging, which means it would provide a Winston logger with @newrelic/winston-enricher, i.e.: my middleware would create a logger and make this available to other middleware and wrapped lambdas.

So how should I do this?:

  • DON'T DO THIS!?
  • attach logger to event?
  • attach logger to context?
  • being able to pass it to next would be nice, e.g. next(null, { logger });?

Most helpful comment

Hey @wrumsby :) you tagged the other luciano :) This is the one you meant: @lmammino
Cheers!

All 7 comments

Hello @wrumsby

Thanks for playing with middy and reaching out here.

Is your logger instance going to be a single global object across all your lambdas (singleton)?

If that's the case you wouldn't need to create a dedicated middleware for it, simply instantiate the logger in a module and require the module when needed.

If instead, you need to create a dedicated instance per lambda invocation then you can indeed create a custom middleware that creates the logger in the before phase and attaches it to the handler object.

Let me know if this helps

Hi @lbertenasco I'm interested in the second case - I'll try something that uses that approach.

Thanks.

Hey @wrumsby :) you tagged the other luciano :) This is the one you meant: @lmammino
Cheers!

@lmammino that approach works using JavaScript. Thanks!

My next challenge is trying to create something that works with TypeScript so that the wrapped handler knows that a logger is available.

Any updates on this?

@wrumsby were you successful in writing a middleware? If it's been open-sourced, we could add it to our community list for others to use and give feedback on if you like. Looks like there is interest.

I am new to middy and hit this. My solution is

import {
    APIGatewayEvent,
    APIGatewayProxyEvent,
    APIGatewayProxyResult,
} from 'aws-lambda/trigger/api-gateway-proxy'
import { Context } from 'aws-lambda/handler'

export const handler =  middy(
    async (event: APIGatewayProxyEvent, _context: Context): Promise<APIGatewayProxyResult> => {
        event.log.info('Executing')
        return { statusCode: 200, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}) }
    })
.use(loggingMiddlware)

const loggingMiddlware: middy.MiddlewareObject<APIGatewayEvent, APIGatewayProxyResult> = {
    async before(handler, _next) {
        handler.event.log = globalLogger.child({ requestId: event.requestId })
    },
}


declare module 'aws-lambda/trigger/api-gateway-proxy' {
    interface APIGatewayProxyEventBase<TAuthorizerContext> {
        log: Logger

        // Hack so TAuthorizerContext is used, cannot prefix with _
        // as it must match the interface exactly for interface merging
        ___: TAuthorizerContext
    }
}
Was this page helpful?
0 / 5 - 0 ratings