Skip to content

Commit 8b97f5a

Browse files
authored
Merge pull request #2639 from bugsnag/PLAT-12567/http-errors-plugin
Create http errors plugin
2 parents 66ae90d + 9488d2e commit 8b97f5a

39 files changed

Lines changed: 9330 additions & 17 deletions

bin/local-test-util

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ async function buildNotifiers (notifier) {
121121
async function packNotifiers (notifier) {
122122
const notifiers = notifier
123123
? [ notifier ]
124-
: [ 'js', 'browser', 'node', 'web-worker', 'plugin-angular', 'plugin-react', 'plugin-vue' ]
124+
: [ 'js', 'browser', 'node', 'web-worker', 'plugin-angular', 'plugin-react', 'plugin-vue', 'plugin-http-errors' ]
125125
for (const n of notifiers) {
126126
let packageLocation = `packages/${n}/`
127127
if (n === 'plugin-angular') packageLocation += 'dist/'
@@ -131,7 +131,7 @@ async function packNotifiers (notifier) {
131131

132132
async function installNotifiers (notifier) {
133133
trace('install notifiers')
134-
if (notifier && ![ 'browser', 'plugin-vue', 'plugin-react', 'web-worker' ].includes(notifier)) return
134+
if (notifier && ![ 'browser', 'plugin-vue', 'plugin-react', 'web-worker', 'plugin-http-errors' ].includes(notifier)) return
135135
await ex(`npm`, [
136136
`install`,
137137
`--no-package-lock`,
@@ -144,7 +144,8 @@ async function installNotifiers (notifier) {
144144
`../../../../bugsnag-browser-${require('../packages/browser/package.json').version}.tgz`,
145145
`../../../../bugsnag-web-worker-${require('../packages/web-worker/package.json').version}.tgz`,
146146
`../../../../bugsnag-plugin-react-${require('../packages/plugin-react/package.json').version}.tgz`,
147-
`../../../../bugsnag-plugin-vue-${require('../packages/plugin-vue/package.json').version}.tgz`
147+
`../../../../bugsnag-plugin-vue-${require('../packages/plugin-vue/package.json').version}.tgz`,
148+
`../../../../bugsnag-plugin-http-errors-${require('../packages/plugin-http-errors/package.json').version}.tgz`
148149
]
149150
), {
150151
cwd: `${__dirname}/../test/browser/features/fixtures`

jest.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ module.exports = {
5050
'plugin-inline-script-content',
5151
'plugin-simple-throttle',
5252
'plugin-console-breadcrumbs',
53-
'plugin-browser-session'
53+
'plugin-browser-session',
54+
'plugin-http-errors'
5455
], {
5556
testEnvironment: '<rootDir>/jest/FixJSDOMEnvironment.js'
5657
}),

package-lock.json

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/core/event.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { App, Device, Event, Request, Breadcrumb, User, Session, FeatureFlag } from './types'
1+
import { App, Device, Event, Request, Response, Breadcrumb, User, Session, FeatureFlag } from './types'
22
import { Error } from './types/event'
33

44
interface HandledState {
@@ -40,6 +40,7 @@ export default class EventWithInternals extends Event {
4040
app: App
4141
device: Device
4242
request: Request
43+
response: Response
4344
breadcrumbs: Breadcrumb[]
4445
context: string | undefined
4546
correlation: { spanId: string, traceId: string } | undefined

packages/core/event.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class Event {
2323
this.app = {}
2424
this.device = {}
2525
this.request = {}
26+
this.response = {}
2627

2728
this.breadcrumbs = []
2829
this.threads = []
@@ -120,6 +121,7 @@ class Event {
120121
app: this.app,
121122
device: this.device,
122123
request: this.request,
124+
response: this.response,
123125
breadcrumbs: this.breadcrumbs,
124126
context: this.context,
125127
groupingHash: this.groupingHash,

packages/core/lib/json-payload.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ const jsonStringify = require('@bugsnag/safe-json-stringify')
22
const EVENT_REDACTION_PATHS = [
33
'events.[].metaData',
44
'events.[].breadcrumbs.[].metaData',
5-
'events.[].request'
5+
'events.[].request',
6+
'events.[].response'
67
]
78

89
module.exports.event = (event, redactedKeys) => {

packages/core/types/common.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ interface Request {
120120
[key: string]: any
121121
}
122122

123+
interface Response {
124+
statusCode: number
125+
headers: { [key: string]: unknown }
126+
body?: string
127+
bodyLength?: number
128+
}
129+
123130
export interface User {
124131
id?: string
125132
email?: string

packages/core/types/event.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
App,
44
Device,
55
Request,
6+
Response,
67
Logger,
78
User,
89
Thread,
@@ -23,6 +24,7 @@ declare class Event {
2324
public app: App
2425
public device: Device
2526
public request: Request
27+
public response: Response
2628

2729
public errors: Error[];
2830
public breadcrumbs: Breadcrumb[]
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2025 Bugsnag
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the "Software"),
5+
to deal in the Software without restriction, including without limitation
6+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
7+
and/or sell copies of the Software, and to permit persons to whom the Software
8+
is furnished to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in
11+
all copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
17+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
18+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
19+
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# @bugsnag/plugin-http-errors
2+
3+
A [@bugsnag/js](https://github.com/bugsnag/bugsnag-js) plugin for HTTP error handling.
4+
5+
## Installation
6+
7+
```sh
8+
npm install --save @bugsnag/plugin-http-errors
9+
# or
10+
yarn add @bugsnag/plugin-http-errors
11+
```
12+
13+
## Usage
14+
15+
```js
16+
import Bugsnag from '@bugsnag/js'
17+
import createHttpErrorPlugin from '@bugsnag/plugin-http-errors'
18+
19+
const plugin = createHttpErrorPlugin({
20+
httpErrorCodes: [401, { min: 404, max: 499 }], // handle individual error codes or ranges of error codes
21+
maxRequestSize: 5_000, // don't capture requests over 5kb
22+
onHttpError: ({ request, response }) => {
23+
// Only handle 5xx errors
24+
if (response.statusCode < 500 || response.statusCode > 599) return false
25+
26+
// Exclude specific domains
27+
if (request.url.indexOf('redacted.domain.com') === 0) return false
28+
29+
// Update properties on the reported request and response
30+
request.url = '[REDACTED]'
31+
response.statusCode = 418
32+
33+
return true // return value will determine whether the error is reported
34+
}
35+
})
36+
37+
Bugsnag.start({
38+
apiKey: 'YOUR_API_KEY',
39+
plugins: [plugin]
40+
})
41+
```
42+
43+
## License
44+
45+
This package is free software released under the MIT License. See [LICENSE.txt](./LICENSE.txt) for details.

0 commit comments

Comments
 (0)