Skip to content

Commit

Permalink
feat: add log-timeout middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
theburningmonk committed Jun 6, 2019
1 parent 1ee0812 commit 02c7710
Show file tree
Hide file tree
Showing 5 changed files with 381 additions and 0 deletions.
40 changes: 40 additions & 0 deletions packages/lambda-powertools-middleware-log-timeout/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# lambda-powertools-middleware-log-timeout

A [Middy](https://github.com/middyjs/middy) middleware that will log a timeout error message **just before** the function actually times out.

Main features:

* records an error log message with the invocation event as attribute when an invocation errors

## Getting Started

Install from NPM: `npm install @perform/lambda-powertools-middleware-log-timeout`

Alternatively, if you use the template `@perform/lambda-powertools-pattern-basic` then this would be configured for you.

## API

Accepts a configuration object of the following shape:

```js
{
// Log the timed out error message this many millis before a function
// actually times out. Defaults to 10ms.
thresholdMillis: double
}
```

```js
const middy = require('middy')
const logTimeout = require('@perform/lambda-powertools-middleware-log-timeout')

const handler = async (event, context) => {
return 42
}

module.exports = middy(handler)
.use(logTimeout())
}
```

It's **recommended** that you use the `@perform/lambda-powertools-pattern-basic` which configures this middleware along with other useful middlewares.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const consoleLog = jest.spyOn(global.console, 'log')

const Promise = require('bluebird')
const middy = require('middy')
const logTimeoutMiddleware = require('../index')

beforeEach(() => {
consoleLog.mockClear()
})

const invokeSuccessHandler = async () => {
const handler = middy(async () => {
})
handler.use(logTimeoutMiddleware())

await handler({}, { awsRequestId: 'test-id' }, () => {})
}

const invokeTimedOutHandler = async (event, awsRequestId) => {
const context = {
awsRequestId,
getRemainingTimeInMillis: () => 20
}

const handler = middy(async () => {
await Promise.delay(20)
})
handler.use(logTimeoutMiddleware())

await new Promise((resolve) => {
handler(event, context, resolve)
})
}

const errorLogWasWritten = (f) => {
expect(consoleLog).toBeCalled()
const log = JSON.parse(consoleLog.mock.calls[0])
expect(log.sLevel).toBe('ERROR')
expect(log.level).toBe(50)
expect(log.message).toBe('invocation timed out')

f(log)
}

describe('Log timeout middleware', () => {
describe('when function finishes successfully', () => {
it('does not log anything', async () => {
await invokeSuccessHandler()
expect(consoleLog).not.toBeCalled()
})
})

describe('when function times out', () => {
it('logs an error message', async () => {
const event = { test: 'wat' }
const awsRequestId = 'test-id'

await invokeTimedOutHandler(event, awsRequestId)

errorLogWasWritten(x => {
expect(x.awsRequestId).toBe(awsRequestId)
expect(x.invocationEvent).toBeDefined()
expect(JSON.parse(x.invocationEvent)).toEqual(event)
})
})
})
})
42 changes: 42 additions & 0 deletions packages/lambda-powertools-middleware-log-timeout/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const Promise = require('bluebird')
const Log = require('@perform/lambda-powertools-logger')

module.exports = (thresholdMillis = 10) => {
let isTimedOut
let promise

const resetPromise = () => {
if (promise) {
promise.cancel()
promise = undefined
}
}

return {
before: (handler, next) => {
const timeLeft = handler.context.getRemainingTimeInMillis()
handler.context.callbackWaitsForEmptyEventLoop = false
isTimedOut = undefined

promise = Promise.delay(timeLeft - thresholdMillis).then(() => {
if (isTimedOut !== false) {
const awsRequestId = handler.context.awsRequestId
const invocationEvent = JSON.stringify(handler.event)
Log.error('invocation timed out', { awsRequestId, invocationEvent })
}
})

next()
},
after: (handler, next) => {
isTimedOut = false
resetPromise()
next()
},
onError: (handler, next) => {
isTimedOut = false
resetPromise()
next(handler.error)
}
}
}
203 changes: 203 additions & 0 deletions packages/lambda-powertools-middleware-log-timeout/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions packages/lambda-powertools-middleware-log-timeout/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "@perform/lambda-powertools-middleware-log-timeout",
"version": "1.0.0",
"description": "Middy middleware to log an error message when a function times out.",
"author": "Yan Cui <theburningmonk@gmail.com>",
"homepage": "https://github.com/getndazn/dazn-lambda-powertools#readme",
"license": "MIT",
"main": "index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/getndazn/dazn-lambda-powertools.git"
},
"scripts": {
"test": "jest"
},
"bugs": {
"url": "https://github.com/getndazn/dazn-lambda-powertools/issues"
},
"dependencies": {
"@perform/lambda-powertools-logger": "^1.1.7",
"bluebird": "^3.5.5"
},
"devDependencies": {
"middy": "^0.15.6"
},
"publishConfig": {
"access": "public"
}
}

0 comments on commit 02c7710

Please sign in to comment.