Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin for Azure Functions #1542

Open
wants to merge 2 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ module.exports = {
'delivery-node',
'in-flight',
'plugin-aws-lambda',
'plugin-azure-functions',
'plugin-express',
'plugin-koa',
'plugin-restify',
Expand Down
65 changes: 65 additions & 0 deletions packages/plugin-azure-functions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# @bugsnag/plugin-azure-functions

A [@bugsnag/js](https://github.com/bugsnag/bugsnag-js) plugin for capturing errors in Azure Functions.

# Install

````
yarn add @bugsnag/plugin-azure-functions
# or
npm install --save @bugsnag/plugin-azure-functions
````

# Usage

To start Bugsnag with the Azure Functions integration, pass the plugin to Bugsnag.start:

````
const Bugsnag = require('@bugsnag/js')
const BugsnagPluginAzureFunctions = require('@bugsnag/plugin-azure-functions')

Bugsnag.start({
plugins: [BugsnagPluginAzureFunctions],
})
````

Start handling errors in your Azure function by wrapping your handler with Bugsnag’s handler:

````
const bugsnagHandler = Bugsnag.getPlugin('azureFunctions').createHandler()

const handler = async (context, req) => {
return {
status: 200,
body: JSON.stringify({ message: 'Hello, World!' })
}
}

module.exports = bugsnagHandler(handler)
````

# Automatically captured data

Bugsnag will automatically capture the Azure function's `context` in the "Azure Functions context" tab on every error.

# Configuration

The Bugsnag Azure Functions plugin can be configured by passing options to createHandler.

**flushTimeoutMs**

Bugsnag will wait for events and sessions to be delivered before allowing the Azure function to exit. This option can be used to control the maximum amount of time to wait before timing out.

By default, Bugsnag will timeout after 2000 milliseconds.

````
const bugsnagHandler = Bugsnag.getPlugin('azureFunctions').createHandler({
flushTimeoutMs: 5000
})
````

If a timeout does occur, Bugsnag will log a warning and events & sessions may not be delivered.

## License

This package is free software released under the MIT License.
36 changes: 36 additions & 0 deletions packages/plugin-azure-functions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "@bugsnag/plugin-azure-functions",
"version": "7.11.0",
"main": "dist/bugsnag-azure-functions.js",
"types": "types/bugsnag-plugin-azure-functions.d.ts",
"description": "Azure Functions support for @bugsnag/node",
"homepage": "https://www.bugsnag.com/",
"repository": {
"type": "git",
"url": "git@github.com:bugsnag/bugsnag-js.git"
},
"publishConfig": {
"access": "public"
},
"files": [
"dist",
"types"
],
"scripts": {
"clean": "rm -fr dist && mkdir dist",
"build": "npm run clean && ../../bin/bundle src/index.js --node --standalone=BugsnagPluginAzureFunctions | ../../bin/extract-source-map dist/bugsnag-azure-functions.js",
"postversion": "npm run build"
},
"author": "Dan Polivy",
"license": "MIT",
"dependencies": {
"@bugsnag/in-flight": "^7.11.0",
"@bugsnag/plugin-browser-session": "^7.11.0"
},
"devDependencies": {
"@bugsnag/core": "^7.11.0"
},
"peerDependencies": {
"@bugsnag/core": "^7.0.0"
}
}
68 changes: 68 additions & 0 deletions packages/plugin-azure-functions/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const bugsnagInFlight = require('@bugsnag/in-flight')
const clone = require('@bugsnag/core/lib/clone-client')

const BugsnagPluginAzureFunctions = {
name: 'azureFunctions',

load (client) {
bugsnagInFlight.trackInFlight(client)

return {
createHandler ({ flushTimeoutMs = 2000 } = {}) {
return wrapHandler.bind(null, client, flushTimeoutMs)
}
}
}
}

// Function which takes in the Azure Function handler and wraps it with
// a new handler that automatically captures unhandled errors
function wrapHandler (client, flushTimeoutMs, handler) {
// Reset the app duration between invocations, if the plugin is loaded
const appDurationPlugin = client.getPlugin('appDuration')

return async function (context, ...args) {
// Get a client to be scoped to this function invocation. If sessions are enabled, use the
// resumeSession() call to get a session client, otherwise, clone the existing client.
const functionClient = client._config.autoTrackSessions ? client.resumeSession() : clone(client)

if (appDurationPlugin) {
appDurationPlugin.reset()
}

// Attach the client to the context
context.bugsnag = functionClient

// Add global metadata attach the context
functionClient.addOnError(event => {
event.addMetadata('Azure Function context', context)
event.clearMetadata('Azure Function context', 'bugsnag')
})

try {
return await handler(context, ...args)
} catch (err) {
if (client._config.autoDetectErrors && client._config.enabledErrorTypes.unhandledExceptions) {
const handledState = {
severity: 'error',
unhandled: true,
severityReason: { type: 'unhandledException' }
}

const event = functionClient.Event.create(err, true, handledState, 'azure functions plugin', 1)

functionClient._notify(event)
}

throw err
} finally {
try {
await bugsnagInFlight.flush(flushTimeoutMs)
} catch (err) {
functionClient._logger.error(`Delivery may be unsuccessful: ${err.message}`)
}
}
}
}

module.exports = BugsnagPluginAzureFunctions
Loading