Skip to content

Commit

Permalink
Merge pull request #252 from MindscapeHQ/develop
Browse files Browse the repository at this point in the history
chore: Release merge 1.1.0
  • Loading branch information
miquelbeltran authored Jun 18, 2024
2 parents ca534df + 2b05cf7 commit b8077b1
Show file tree
Hide file tree
Showing 15 changed files with 607 additions and 470 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## 1.1.0

- feat: Part of #220 add internal runWithBreadcrumbsAsync function (#245) (2024-06-05)
- fix: onBeforeSend allows to skip messages (#231) (2024-05-28)
- chore(deps-dev): bump @eslint/js from 9.3.0 to 9.4.0 (#243) (2024-06-03)
- chore(deps-dev): bump @types/node from 20.12.12 to 20.14.0 (#242) (2024-06-03)
- chore(deps-dev): bump prettier from 3.2.5 to 3.3.0 (#241) (2024-06-03)
- chore(deps): bump debug from 4.3.4 to 4.3.5 (#240) (2024-06-03)
- chore(deps-dev): bump typescript-eslint from 7.10.0 to 7.11.0 (#239) (2024-06-03)
- chore(deps-dev): bump tap from 18.8.0 to 19.0.2 (#237) (2024-05-28)
- chore(deps-dev): bump typescript-eslint from 7.9.0 to 7.10.0 (2024-05-27)

## 1.0.0

- feat: #219 Better Send parameters (#221) (2024-05-17)
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,18 +287,18 @@ Call `Raygun.onBeforeSend()`, passing in a function which takes up to 5 paramete

You can also pass this in as an option to `init()` like this: `raygunClient.init({ onBeforeSend: function(payload) { return payload; } });`

From the supplied function, you should return either the payload (intact or mutated as per your needs), or false.
From the supplied function, you should return either the payload (intact or mutated as per your needs), or `null`.

If your function returns a truthy object, Raygun4Node will attempt to send it as supplied. Thus, you can mutate it as per your needs - preferably only the values if you wish to filter out data that is not taken care of by the filters. You can also of course return it as supplied.

If, after inspecting the payload, you wish to discard it and abort the send to Raygun, simply return false.
If, after inspecting the payload, you wish to discard it and abort sending it to Raygun, simply return `null`.

By example:
For example:

```javascript
const myBeforeSend = function (payload, exception, customData, request, tags) {
console.log(payload); // Modify the payload here if necessary
return payload; // Return false here to abort the send
return payload; // Return null here instead of payload to abort the send
}

Raygun.onBeforeSend(myBeforeSend);
Expand Down
15 changes: 15 additions & 0 deletions examples/express-sample/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,21 @@ app.use("/users", users);
// Add the Raygun error Express handler
app.use(raygunClient.expressHandler);

// Optional: Configure onBeforeSend
raygunClient.onBeforeSend((message, exception, customData, request, tags) => {
console.log(
`[app.js] onBeforeSend called with error: ${message.details.error.message}`,
);

// If the message contains the word "skip", do not send the message to Raygun
if (message.details.error.message.indexOf("skip") > -1) {
console.log("[app.js] skip sending message");
return null;
}

return message;
});

raygunClient.addBreadcrumb("Express Server started!");

module.exports = app;
17 changes: 17 additions & 0 deletions examples/express-sample/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ router.get("/", function (req, res, next) {
});
});

router.get("/skip", function (req, res, next) {
raygunClient
.send("Error to skip")
.then((message) => {
res.render("send", {
title: "Skip sending message",
body: `Message should be null: ${message}`,
});
})
.catch((error) => {
res.render("send", {
title: "Failed to send error to Raygun",
body: error.toString(),
});
});
});

router.get("/send", function (req, res, next) {
raygunClient.addBreadcrumb({
level: "debug",
Expand Down
3 changes: 3 additions & 0 deletions examples/express-sample/views/index.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
<div>
<a href="/send">Send a custom error</a>
</div>
<div>
<a href="/skip">Skip sending an error after inspecting it via onBeforeSend</a>
</div>
<div>
<a href="/error">Throw an error</a>
</div>
Expand Down
16 changes: 15 additions & 1 deletion lib/raygun.breadcrumbs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ export function addBreadcrumb(
lineNumber: callsite?.lineNumber || undefined,
};

debug(`[raygun.breadcrumbs.ts] recorded breadcrumb: ${internalCrumb}`);
debug(
`[raygun.breadcrumbs.ts] recorded breadcrumb: ${internalCrumb.message}`,
);

crumbs.push(internalCrumb);
}
Expand Down Expand Up @@ -127,6 +129,18 @@ export function runWithBreadcrumbs(f: () => void, store: Breadcrumb[] = []) {
asyncLocalStorage.run(store, f);
}

export function runWithBreadcrumbsAsync<T>(
f: () => Promise<T>,
store: Breadcrumb[] = [],
): Promise<T> {
if (!asyncLocalStorage) {
return f();
}

debug("[raygun.breadcrumbs.ts] running async function with breadcrumbs");
return asyncLocalStorage.run(store, f);
}

export function clear() {
if (!asyncLocalStorage) {
return;
Expand Down
66 changes: 54 additions & 12 deletions lib/raygun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import * as raygunSyncTransport from "./raygun.sync.transport";
import { v4 as uuidv4 } from "uuid";

type SendOptionsResult =
| { valid: true; message: Message; options: SendOptions }
| { valid: true; message: Message; options: SendOptions; skip: boolean }
| { valid: false; message: Message };

const debug = require("debug")("raygun");
Expand Down Expand Up @@ -81,7 +81,7 @@ class Raygun {

_useSSL: boolean | undefined;

_onBeforeSend: Hook<Message> | undefined;
_onBeforeSend: Hook<Message | null> | undefined;

_offlineStorage: IOfflineStorage | undefined;

Expand Down Expand Up @@ -175,7 +175,12 @@ class Raygun {
return this;
}

onBeforeSend(onBeforeSend: Hook<Message>) {
/**
* Access or mutate the candidate error payload immediately before it is sent,
* or skip the sending action by returning null.
* @param onBeforeSend callback that must return a Message object to send, or null to skip sending it.
*/
onBeforeSend(onBeforeSend: Hook<Message | null>) {
this._onBeforeSend = onBeforeSend;
return this;
}
Expand Down Expand Up @@ -250,6 +255,13 @@ class Raygun {
return Promise.reject(sendOptionsResult.message);
}

if (sendOptionsResult.skip) {
console.log(
`[Raygun4Node] Skip sending message: ${sendOptionsResult.message.details.error}.`,
);
return Promise.resolve(null);
}

const sendOptions = sendOptionsResult.options;
if (this._isOffline) {
// Server is offline, store in Offline Storage
Expand Down Expand Up @@ -337,21 +349,40 @@ class Raygun {
return;
}

// Handles uncaught exceptions, e.g. missing try/catch on a throw.
process.on("uncaughtExceptionMonitor", (e) => {
this.sendSync(e);
this.sendSync(e, ["uncaughtException"]);
});

// Handles uncaught Promise rejections, e.g. missing .catch(...) on a Promise.
// Unhandled Promise rejections are not caught by the "uncaughtExceptionMonitor".
process.on("unhandledRejection", (reason, promise) => {
if (reason instanceof Error || typeof reason === "string") {
this.sendSync(reason, ["unhandledRejection"]);
} else {
// `reason` type is unknown, wrap in String
this.sendSync(`Unhandled Rejection: ${reason}`, ["unhandledRejection"]);
}
});
}

/**
* Send error using synchronous transport.
* Only used to report uncaught exceptions.
* Only used internally to report uncaught exceptions or unhandled promises.
* @param exception error to report
* @param tags optional tags
* @private
*/
private sendSync(exception: Error | string): void {
const result = this.buildSendOptions(exception);
private sendSync(exception: Error | string, tags?: Tag[]): void {
const result = this.buildSendOptions(exception, null, undefined, tags);

if (result.valid) {
if (result.skip) {
console.log(
`[Raygun4Node] Skip sending message: ${result.message.details.error}.`,
);
return;
}
raygunSyncTransport.send(result.options);
}
}
Expand Down Expand Up @@ -446,6 +477,7 @@ class Raygun {
tags?: Tag[],
): SendOptionsResult {
let mergedTags: Tag[] = [];
let skip = false;

if (this._tags) {
mergedTags = mergedTags.concat(this._tags);
Expand Down Expand Up @@ -480,11 +512,20 @@ class Raygun {
: null;
}

if (this._onBeforeSend) {
message =
typeof this._onBeforeSend === "function"
? this._onBeforeSend(message, exception, customData, request, tags)
: message;
if (this._onBeforeSend && typeof this._onBeforeSend === "function") {
const _message = this._onBeforeSend(
message,
exception,
customData,
request,
tags,
);
if (_message) {
message = _message;
} else {
debug("[raygun.ts] onBeforeSend returned null, cancelling send");
skip = true;
}
}

if (apmBridge) {
Expand All @@ -503,6 +544,7 @@ class Raygun {
return {
valid: true,
message,
skip: skip,
options: {
message: JSON.stringify(message),
http: {
Expand Down
Loading

0 comments on commit b8077b1

Please sign in to comment.