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

chore: Version 1.0.0 #233

Merged
merged 18 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d8ec309
refactor: #197 Refactor to use Promises internally (#200)
miquelbeltran May 9, 2024
f4ae131
refactor: #205 Setup eslint style (#207)
miquelbeltran May 9, 2024
e14deec
docs: Update status badge in README.md (#209)
miquelbeltran May 10, 2024
61a9539
chore(deps-dev): bump semver from 7.6.0 to 7.6.2 (#211)
dependabot[bot] May 13, 2024
fc09498
chore(deps-dev): bump @types/node from 20.12.8 to 20.12.11 (#212)
dependabot[bot] May 13, 2024
641bb4c
chore(deps-dev): bump tap from 18.7.2 to 18.8.0 (#213)
dependabot[bot] May 13, 2024
a95d14c
chore(deps-dev): bump @stylistic/eslint-plugin from 2.0.0 to 2.1.0 (#…
dependabot[bot] May 13, 2024
57ceec3
feat: Breadcrumbs (#210)
miquelbeltran May 15, 2024
77b8229
feat: #219 Better Send parameters (#221)
miquelbeltran May 17, 2024
ed8aee9
chore: apply prettier to all files in examples (#226)
miquelbeltran May 19, 2024
c322f01
fix: #138 New APM Bridge Setup (#222)
miquelbeltran May 20, 2024
a80e8dd
chore: code cleanup (#225)
miquelbeltran May 20, 2024
9ebcc4e
chore(deps-dev): bump @types/node from 20.12.11 to 20.12.12 (#227)
dependabot[bot] May 20, 2024
d147888
chore(deps-dev): bump @eslint/js from 9.2.0 to 9.3.0 (#228)
dependabot[bot] May 20, 2024
3fb1482
chore(deps-dev): bump typescript-eslint from 7.8.0 to 7.9.0 (#229)
dependabot[bot] May 20, 2024
8e37c10
chore: Prepare Release 1.0.0 (#230)
miquelbeltran May 23, 2024
f5c1307
fix: Fixes in 1.0.0 release candidate (#234)
miquelbeltran May 24, 2024
188d9c9
chore: Revert PR #222 (fix: #138 New APM Bridge Setup) (#235)
miquelbeltran May 27, 2024
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
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
## 1.0.0

- feat: #219 Better Send parameters (#221) (2024-05-17)
- feat: Breadcrumbs (#210) (2024-05-15)
- fix: #138 New APM Bridge Setup (#222) (2024-05-20)
- docs: Update status badge in README.md (#209) (2024-05-10)
- refactor: #205 Setup eslint style (#207) (2024-05-09)
- refactor: #197 Refactor to use Promises internally (#200) (2024-05-09)
- refactor: #184 Cleanup debug/log messages and styles (#194) (2024-05-08)
- chore(deps-dev): bump typescript-eslint from 7.8.0 to 7.9.0 (#229) (2024-05-20)
- chore(deps-dev): bump @eslint/js from 9.2.0 to 9.3.0 (#228) (2024-05-20)
- chore(deps-dev): bump @types/node from 20.12.11 to 20.12.12 (#227) (2024-05-20)
- chore(deps-dev): bump @stylistic/eslint-plugin from 2.0.0 to 2.1.0 (#214) (2024-05-13)
- chore(deps-dev): bump tap from 18.7.2 to 18.8.0 (#213) (2024-05-13)
- chore(deps-dev): bump @types/node from 20.12.8 to 20.12.11 (#212) (2024-05-13)
- chore(deps-dev): bump semver from 7.6.0 to 7.6.2 (#211) (2024-05-13)
- chore: code cleanup (#225) (2024-05-20)
- chore: apply prettier to all files in examples (#226) (2024-05-19)

**BREAKING CHANGES**
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we support a backwards-compatible but deprecated (and to be removed next) send method? With some additional checking logic, it could as simple as function send(error, customData={}, request,={} tags={}){ return send(error, {customData: customData, request: request, tags: tags});}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it makes sense to add in the deprecation, we could do this now whilst we discuss the final decision. It looks like we've done something in the past about deprecating (which we may need to remove -

// This function is deprecated, is provided for legacy apps and will be
)

Copy link
Contributor Author

@miquelbeltran miquelbeltran May 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We provide a backwards compatible method, is sendWithCallback().

raygun4node/lib/raygun.ts

Lines 292 to 318 in 8e37c10

/**
* @deprecated sendWithCallback is a deprecated method. Instead, use send, which supports async/await calls.
*/
sendWithCallback(
exception: Error | string,
customData?: CustomData,
callback?: Callback<IncomingMessage>,
request?: RequestParams,
tags?: Tag[],
) {
// call async send but redirect response to provided legacy callback
this.send(exception, {
customData,
request,
tags,
})
.then((response) => {
if (callback) {
callVariadicCallback(callback, null, response);
}
})
.catch((error) => {
if (callback) {
callVariadicCallback(callback, error, null);
}
});
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could as simple as function send(error, customData={}, request,={} tags={}){ return send(error, {customData: customData, request: request, tags: tags});}

JavaScript doesn't support overloading methods. There ware some workarounds but have limitations.


- `send()` method signature changed.
- APM Bridge setup process changed.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What were we doing before and as above, can we support a deprecated version?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous setup process was causing compilation errors to some users and was not possible to properly unit test it, it is explained in detail here: #222


See README.md for more information.

## 0.15.0-0
- async/await `send()` support
- Upgrade dependencies
Expand Down
95 changes: 86 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Raygun4Node

[![Build Status](https://travis-ci.org/MindscapeHQ/raygun4node.svg?branch=master)](https://travis-ci.org/MindscapeHQ/raygun4node)
[![GitHub CI](https://github.com/MindscapeHQ/raygun4node/actions/workflows/node.js.yml/badge.svg)](https://github.com/MindscapeHQ/raygun4node/actions)

Raygun.io package for Node, written in TypeScript.
Raygun.com package for Node, written in TypeScript.

# Where is my app API key?

Expand Down Expand Up @@ -141,12 +141,23 @@ The callback should be a node-style callback: `function(err, response) { /*...*/
it will only be called when the transmission is successful. This is included for
backwards compatibility; the Node-style callback should be preferred.

### Send Parameters

The `send()` method accepts a series of optional named parameters, defined as follows:

```js
client.send(error, { customData, request, tags });
```

Each one of these parameters is optional.
They are explained in detail the following sections.

miquelbeltran marked this conversation as resolved.
Show resolved Hide resolved
### Sending custom data

You can pass custom data in on the Send() function, as the second parameter. For instance (based off the call in test/raygun_test.js):
You can pass custom data in on the Send() function, as the `customData` parameter. For instance (based off the call in test/raygun_test.js):

```javascript
client.send(new Error(), { 'mykey': 'beta' });
client.send(new Error(), { customData: { 'mykey': 'beta' } });
```

#### Sending custom data with Expressjs
Expand All @@ -163,9 +174,10 @@ raygunClient.expressCustomData = function (err, req) {

### Sending request data

You can send the request data in the Send() function, as the fourth parameter. For example:
You can send the request data in the Send() function, as the `request` parameter. For example:

```javascript
client.send(new Error(), {}, request);
client.send(new Error(), { request: request });
```

If you want to filter any of the request data then you can pass in an array of keys to filter when
Expand All @@ -177,9 +189,10 @@ const raygunClient = new raygun.Client().init({ apiKey: 'YOUR_API_KEY', filters:

### Tags

You can add tags to your error in the Send() function, as the fifth parameter. For example:
You can add tags to your error in the Send() function, as the `tags` parameter. For example:

```javascript
client.send(new Error(), {}, {}, ['Custom Tag 1', 'Important Error']);
client.send(new Error(), { tags: ['Custom Tag 1', 'Important Error'] });
```

Tags can also be set globally using setTags
Expand Down Expand Up @@ -266,7 +279,7 @@ This feature is preferable to using the `domains` module for this purpose, as `d

### Changing the API endpoint

You can change the endpoint that error messages are sent to by specifying the `host`, `port`, and `useSSL` properties in the `raygunClient.init()` options hash. By default, `host` is `api.raygun.io`, `port` is `443`, and `useSSL` is `true`.
You can change the endpoint that error messages are sent to by specifying the `host`, `port`, and `useSSL` properties in the `raygunClient.init()` options hash. By default, `host` is `api.raygun.com`, `port` is `443`, and `useSSL` is `true`.

### onBeforeSend

Expand All @@ -291,6 +304,66 @@ const myBeforeSend = function (payload, exception, customData, request, tags) {
Raygun.onBeforeSend(myBeforeSend);
```

### Breadcrumbs

Breadcrumbs can be sent to Raygun to provide additional information to look into and debug issues stemming from crash reports.

Breadcrumbs can be created in two ways.

#### Simple string:

Call `client.addBreadcrumb(message)`, where message is just a string:

```js
client.addBreadcrumb('test breadcrumb');
```

#### Using `BreadcrumbMessage`:

Create your own `BreadcrumbMessage` object and send more than just a message with `client.addBreadcrumb(BreadcrumbMessage)`.

The structure of the type `BreadcrumbMessage` is as shown here:

```js
BreadcrumbMessage: {
level: "debug" | "info" | "warning" | "error";
category: string;
message: string;
customData?: CustomData;
}
```

#### Sending Breadcrumbs

When an error message is sent to Raygun Crash Reporting, all the registered Breadcrumbs will be attached automatically.

After the error message has been sent, the registered Breadcrumbs list be cleared automatically.

Otherwise, you can also clear Breadcrumbs with `client.clearBreadcrumbs()`.

#### Breadcrumbs and ExpressJS

Raygun4Node provides a custom ExpressJS middleware that helps to scope Breadcrumbs to a specific request.
As well, this middleware will add a Breadcrumb with information about the performed request.

To set up, add the Raygun Breadcrumbs ExpressJS handler before configuring any endpoints.

```js
// Add the Raygun Breadcrumb ExpressJS handler
app.use(raygunClient.expressHandlerBreadcrumbs);

// Setup the rest of the app, e.g.
app.use("/", routes);
```

This middleware can be used together with the provided ExpressJS error handler `expressHandler`.
The order in which the middlewares are configured is important. `expressHandlerBreadcrumbs` must go first to scope breadcrumbs correctly.

```js
app.use(raygunClient.expressHandlerBreadcrumbs);
app.use(raygunClient.expressHandler);
```

### Batched error transport

You can enable a batched transport mode for the Raygun client by passing `{batch: true}` when initializing.
Expand Down Expand Up @@ -477,6 +550,10 @@ curl

All requests use the same authentication methods as the upload call (Basic Authentication and Token Authentication).

### Known Issues

- Node will show compilation warnings when using Raygun4Node in Webpack applications.

### Examples
View a screencast on creating an app with Node.js and Express.js, then hooking up the error handling and sending them at [https://raygun.com/blog/2013/07/video-nodejs-error-handling-with-raygun/](https://raygun.com/blog/2013/07/video-nodejs-error-handling-with-raygun/)

Expand Down
30 changes: 30 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
// @ts-check

import eslint from '@eslint/js';
import stylistic from '@stylistic/eslint-plugin';
import stylisticTs from '@stylistic/eslint-plugin-ts';
import tseslint from 'typescript-eslint';

export default tseslint.config(
// Basic eslint rules
eslint.configs.recommended,
// Codestyle rules for JS
stylistic.configs["recommended-flat"],
// Codestyle rules for TS
stylisticTs.configs["all-flat"],
// Eslint rules for TS
...tseslint.configs.recommended,
{
languageOptions: {
// Add node globals to ignore undefined
globals: {
"__dirname": false,
"__filename": false,
"console": false,
"module": false,
"process": false,
Expand All @@ -29,6 +38,27 @@ export default tseslint.config(
],
// Required to import JS modules
"@typescript-eslint/no-var-requires": "off",
// Always require semicolons
"@stylistic/semi": ["error", "always"],
// Stick to double quotes
"@stylistic/quotes": ["error", "double"],
// Always indent with two spaces
'@stylistic/ts/indent': ['error', 2],
// Enforce curly braces spacing
"@stylistic/ts/object-curly-spacing": ["error", "always"],
// Enforce "one true brace style"
"@stylistic/brace-style": ["error", "1tbs"],
// Enforce parenthesis in functions: "(a) => a"
"@stylistic/arrow-parens": ["error", "always"],
// Disabled rules that collide with Prettier formatter
"@stylistic/member-delimiter-style": ["off", 0],
"@stylistic/no-mixed-operators": ["off", 0],
"@stylistic/operator-linebreak": ["off", 0],
"@stylistic/quote-props": ["off", 0],
"@stylistic/ts/comma-dangle": ["off", 0],
"@stylistic/ts/no-extra-parens": ["off", 0],
"@stylistic/ts/quote-props": ["off", 0],
"@stylistic/ts/space-before-function-paren": ["off", 0],
}
}
);
11 changes: 7 additions & 4 deletions examples/express-sample/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ in the subdirectory where you found this README.md file.

## Interesting files to look

- `raygun.client.js`
- Setup of Raygun (lines 9-14)
- `app.js`
- Setup of Raygun (lines 9-12)
- Sets the user (lines 27-29)
- Attaches Raygun to Express (line 60)
- Sets the user (lines 17-19)
- Attaches Raygun Breadcrumb middleware to Express (line 26)
- Attaches Raygun to Express (line 53)
- `routes/index.js`
- Tries to use a fake object, which bounces up to the Express handler (lines 11-15)
- `/send` endpoint: Sends a custom error to Raygun (lines 11-34)
- `/error` endpoint: Tries to use a fake object, which bounces up to the Express handler (lines 36-49)
27 changes: 9 additions & 18 deletions examples/express-sample/app.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,11 @@
var config = require("config");

if (config.Raygun.Key === "YOUR_API_KEY") {
console.error(
`[Raygun4Node-Express-Sample] You need to set your Raygun API key in the config file`,
);
process.exit(1);
}

// Setup Raygun
var raygun = require("raygun");
var raygunClient = new raygun.Client().init({
apiKey: config.Raygun.Key,
});

var express = require("express");
var path = require("path");
var favicon = require("serve-favicon");
var logger = require("morgan");
var cookieParser = require("cookie-parser");
var bodyParser = require("body-parser");
var sassMiddleware = require("node-sass-middleware");
var raygunClient = require("./raygun.client");

var routes = require("./routes/index");
var users = require("./routes/users");
Expand All @@ -34,8 +21,10 @@ raygunClient.user = function (req) {
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "ejs");

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
// Add the Raygun breadcrumb Express handler
app.use(raygunClient.expressHandlerBreadcrumbs);

app.use(favicon(__dirname + "/public/favicon.ico"));
app.use(logger("dev"));
app.use(bodyParser.json());
app.use(
Expand All @@ -58,7 +47,9 @@ app.use(express.static(path.join(__dirname, "public")));
app.use("/", routes);
app.use("/users", users);

// Add the Raygun Express handler
// Add the Raygun error Express handler
app.use(raygunClient.expressHandler);

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

module.exports = app;
40 changes: 21 additions & 19 deletions examples/express-sample/bin/www
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
* Module dependencies.
*/

var app = require('../app');
var debug = require('debug')('express-sample:server');
var http = require('http');
var app = require("../app");
var debug = require("debug")("express-sample:server");
var http = require("http");

/**
* Get port from environment and store in Express.
*/

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
var port = normalizePort(process.env.PORT || "3000");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the user does not use process.env.PORT to set up Express? Should we be pulling this elsewhere, if possible?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is an example app, we should not have to worry about this? 🤔 We are using the standard way to set up ports I would think. Happy to be challenged! Such as, what other way would people use commonly :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

process.env.PORT || "3000" works that if the user doesn't have a $PORT in their env vars, 3000 will be used by default.

Yes, agreed with @sumitramanga I guess this is standard express:

image

app.set("port", port);

/**
* Create HTTP server.
Expand All @@ -26,8 +26,8 @@ var server = http.createServer(app);
*/

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
server.on("error", onError);
server.on("listening", onListening);

/**
* Normalize a port into a number, string, or false.
Expand All @@ -54,22 +54,26 @@ function normalizePort(val) {
*/

function onError(error) {
if (error.syscall !== 'listen') {
if (error.syscall !== "listen") {
throw error;
}

var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port
var bind = typeof port === "string" ? "Pipe " + port : "Port " + port;

// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(`[Raygun4Node-Express-Sample] ` + bind + ` requires elevated privileges`);
case "EACCES":
console.error(
`[Raygun4Node-Express-Sample] ` +
bind +
` requires elevated privileges`,
);
process.exit(1);
break;
case 'EADDRINUSE':
console.error(`[Raygun4Node-Express-Sample] ` + bind + ` is already in use`);
case "EADDRINUSE":
console.error(
`[Raygun4Node-Express-Sample] ` + bind + ` is already in use`,
);
process.exit(1);
break;
default:
Expand All @@ -83,8 +87,6 @@ function onError(error) {

function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
var bind = typeof addr === "string" ? "pipe " + addr : "port " + addr.port;
debug("Listening on " + bind);
}
8 changes: 4 additions & 4 deletions examples/express-sample/config/default.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"Raygun": {
"Key": "YOUR_API_KEY"
}
}
"Raygun": {
"Key": "YOUR_API_KEY"
}
}
Loading