![npm version](https://img.shields.io/npm/types/toucan-js)
toucan-js
Toucan is a Sentry client for Cloudflare Workers written in TypeScript.
Usage
npm install --save toucan-js
FetchEvent
import Toucan from 'toucan-js';
addEventListener('fetch', (event) => {
const sentry = new Toucan({
dsn: 'dsn...',
context: event,
allowedHeaders: ['user-agent'],
allowedSearchParams: /(.*)/,
});
sentry.setUser({ id: '1234' });
event.respondWith(async () => {
try {
return new Response('OK', {
status: 200,
statusText: 'OK',
});
} catch (err) {
sentry.captureException(err);
return new Response('Something went wrong', {
status: 500,
statusText: 'Internal Server Error',
});
}
});
});
ScheduledEvent
import Toucan from 'toucan-js';
addEventListener('scheduled', (event) => {
const sentry = new Toucan({
dsn: 'dsn...',
context: event,
});
event.waitUntil(async () => {
try {
} catch (err) {
sentry.captureException(err);
}
});
});
Equivalent of above as a module (.mjs)
import Toucan from 'toucan-js';
export default {
async fetch(request: Request, env: Env, context: Context) {
const sentry = new Toucan({
dsn: 'dsn...',
context: event,
request,
allowedHeaders: ['user-agent'],
allowedSearchParams: /(.*)/,
});
try {
return new Response('OK', {
status: 200,
statusText: 'OK',
});
} catch (err) {
sentry.captureException(err);
return new Response('Something went wrong', {
status: 500,
statusText: 'Internal Server Error',
});
}
},
async scheduled(controller: Controller, env: Env, context: Context) {
const sentry = new Toucan({
dsn: 'dsn...',
context: event,
});
event.waitUntil(async () => {
try {
} catch (err) {
sentry.captureException(err);
}
});
},
};
Durable Objects
import Toucan from 'toucan-js';
export class DurableObjectExample {
state: DurableObjectState;
constructor(state: DurableObjectState, env: Env) {
this.state = state;
}
async fetch(request: Request) {
const sentry = new Toucan({
dsn: 'dsn...',
request,
allowedHeaders: ['user-agent'],
allowedSearchParams: /(.*)/,
context: this.state,
});
try {
return new Response('OK', {
status: 200,
statusText: 'OK',
});
} catch (err) {
sentry.captureException(err);
return new Response('Something went wrong', {
status: 500,
statusText: 'Internal Server Error',
});
}
}
}
Features
- addBreadcumb: Records a new breadcrumb which will be attached to future events.
- captureException: Captures an exception event and sends it to Sentry.
- captureMessage: Captures a message event and sends it to Sentry.
- setRequestBody: Records incoming request's body which will be attached to future events.
- setTag: Set key:value that will be sent as tags data with the event.
- setTags: Set an object that will be merged sent as tags data with the event.
- setExtra: Set key:value that will be sent as extra data with the event.
- setExtras: Set an object that will be merged sent as extra data with the event.
- setUser: Updates user context information for future events.
- setFingerprint: Overrides the Sentry default grouping.
- withScope: Creates a new scope and executes the given operation within. The scope is automatically removed once the operation finishes or throws.
Minimal options
Other options
Option | Type | Description |
---|
allowedCookies | string[] | RegExp | Array of allowed cookies, or a regular expression used to explicitly allow cookies of incoming request. If not provided, cookies will not be logged. No effect without request in context. |
allowedHeaders | string[] | RegExp | Array of allowed headers, or a regular expression used to explicitly allow headers of incoming request. If not provided, headers will not be logged. No effect without request in context. |
allowedSearchParams | string[] | RegExp | Array of allowed search params, or a regular expression used to explicitly allow search params of incoming request. If not provided, search params will not be logged. No effect without request in context. |
attachStacktrace | boolean | Attaches stacktraces to capture message. Default true. |
beforeSend | (event: Event) => Event | This function is applied to all events before sending to Sentry. If provided, all allowlists are ignored. |
debug | boolean | Turns debug mode on or off. If debug is enabled, toucan-js will attempt to print out useful debugging information. |
environment | string | Your application's environment (production/staging/...). |
maxBreadcrumbs | number | This variable controls the total amount of breadcrumbs that should be captured. This defaults to 100. |
pkg | object | Essentially your package.json. Toucan will use it to read project name, version, dependencies, and devDependencies. |
release | string | Release tag. |
request | Request | You will want to use this option in Durable Object or .mjs Worker, where request isn't included in context . |
rewriteFrames | { root?: string, iteratee?: (frame: StackFrame) => StackFrame } | Allows you to apply a transformation to each frame of the stack trace. root path will be appended to the basename of the current frame's url. iteratee is a function that takes the frame, applies any transformation on it and returns it back. |
sampleRate | number | Configures the sample rate as a percentage of events to be sent in the range of 0.0 to 1.0. The default is 1.0 which means that 100% of events are sent. If set to 0.1 only 10% of events will be sent. Events are picked randomly. |
transportOptions | { headers?: Record<string, string> } | Custom headers to be passed to Sentry. |
Sensitive data
By default, Toucan does not send any Request property that could carry PII (Personally Identifiable Information) to Sentry.
This includes:
- All request Headers
- All request Cookies
- All request search params
- Request body
You will need to explicitly allow these data using:
- allowedHeaders option (array of headers or Regex)
- allowedCookies option (array of cookies or Regex)
- allowedSearchParams option (array of search params or Regex)
- toucan.setRequestBody function
- beforeSend option (if you need more flexibility than allowedX functions)
Known issues
Source Maps
Make sure to use the absolute paths on the stack frames and Sentry's artifacts, the default ~/
will not match them properly. Any absolute path will work (i.e., /
). You will need to use rewriteFrames
option to add the prefix to the stack frames.
const toucan = new Toucan({
dsn: ...
event,
rewriteFrames: {
root: '/'
}
}
Changing the Sentry's artifacts URL depends on plugin you use to upload your source maps.
Example configuration using @sentry/webpack-plugin
:
const SentryWebpackPlugin = require('@sentry/webpack-plugin');
const pkg = require('./package.json');
module.exports = {
entry: './src/index.ts',
target: 'webworker',
devtool: 'source-map',
plugins: [
new SentryWebpackPlugin({
release: `${pkg.name}-${pkg.version}`,
include: './dist',
urlPrefix: '/',
}),
],
};
For more information, see this issue.