-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: James Sumners <[email protected]>
- Loading branch information
1 parent
e7a78c4
commit 44dbdbb
Showing
10 changed files
with
275 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Example instrumentation of a basic app | ||
|
||
This example application shows you how to use the [newrelic.instrument](https://newrelic.github.io/node-newrelic/API.html#instrument) and associated [shim](https://newrelic.github.io/node-newrelic/Shim.html) API. It instruments a simple module, a rudimentary job queue (`jobQueue`), and runs a series of basic jobs. | ||
|
||
## Getting Started | ||
|
||
1. Clone or fork this repository. | ||
2. Navigate to this example's sub directory | ||
``` | ||
cd newrelic-node-examples/custom-instrumentation/instrument | ||
``` | ||
3. Install dependencies and run application. | ||
``` | ||
npm install | ||
cp env.sample .env | ||
# Fill out `NEW_RELIC_LICENSE_KEY` in .env and save | ||
# Start the application | ||
npm start | ||
``` | ||
4. The app will automatically start adding example jobs to a queue and run them. You should see the following in the console when the instrumentation takes place. | ||
``` | ||
[NEWRELIC] instrumenting 'job-queue' | ||
Callback job done | ||
Promise job done | ||
``` | ||
|
||
## Exploring Telemetry | ||
|
||
1. After a few minutes, you should be able to see `job-queue` instrumented in New Relic. From the dashboard, navigate to 'APM & Services' and then select the 'Example Job Queue App' entity. | ||
2. Then select 'Distributed tracing'. You should see the trace groups `firstTransacation`, `secondTransaction`, and `thirdTransaction`. Inside these groups will be our custom instrumentation. Select any trace group and then select a single trace. | ||
3. Under `firstTransaction` or `secondTransaction`, toggle 'Show in-process spans' and you will see 'scheduleJob - job'; this shows the name of which job was recorded. Under `thirdTransaction`, you will see `queue.runJobs` instrumented as 'runJobs'. | ||
|
||
![1722869774240](./image/README/1722869774240.png) | ||
|
||
![1722869857647](./image/README/1722869857647.png) | ||
|
||
## Description | ||
|
||
This application consists of the following files: | ||
|
||
* `index.js`: a simple app that schedules jobs and runs them | ||
* `job-queue.js`: an example module that provides a queue class that you can use to run and schedule jobs | ||
* `instrumentation.js`: all of the New Relic instrumentation is in here; the `npm start` command makes sure this module is loaded first | ||
* `newrelic.js`: a basic, sample New Relic configurartion |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
NEW_RELIC_LICENSE_KEY= |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
* Copyright 2024 New Relic Corporation. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
'use strict' | ||
|
||
const newrelic = require('newrelic') | ||
const Queue = require('./job-queue') | ||
|
||
function exampleJob() { | ||
// Do whatever work you want here - this is just a placeholder | ||
return 'job done'; | ||
} | ||
|
||
function cbJob(cb) { | ||
const result = exampleJob(); | ||
return cb('Callback ' + result); | ||
} | ||
|
||
async function promiseJob() { | ||
return new Promise((resolve, reject) => { | ||
try { | ||
const result = exampleJob() | ||
resolve('Promise ' + result) | ||
} | ||
catch (error) { | ||
reject(error) | ||
} | ||
}) | ||
} | ||
|
||
function main() { | ||
const queue = new Queue() | ||
|
||
// We will be creating our transactions with startBackgroundTransaction | ||
// because this application does not utilize frameworks New Relic already | ||
// instruments. Thus, transactions are not automatically created for use. | ||
// If you are already operating within an instrumented framework, you may | ||
// omit the startBackgroundTransaction wrapper. | ||
|
||
// Without instrumentation, executing this code will cause 'firstTransaction' | ||
// to be the active transaction in both 'firstJob' and 'secondJob'. This is | ||
// not the intended behavior. If we instrument queue.scheduleJob, the | ||
// functions will be correctly placed within their respective transactions. | ||
newrelic.startBackgroundTransaction('firstTransaction', function () { | ||
const transaction = newrelic.getTransaction() | ||
queue.scheduleJob(async function firstJob() { | ||
// Do some work - for example, this waits for a promise job to complete | ||
const result = await promiseJob() | ||
console.log(result) | ||
transaction.end() | ||
}) | ||
}) | ||
|
||
newrelic.startBackgroundTransaction('secondTransaction', function () { | ||
const transaction = newrelic.getTransaction() | ||
queue.scheduleJob(function secondJob() { | ||
// Do some work - for example, this waits for a callback job to complete | ||
cbJob(function cb(result) { | ||
console.log(result) | ||
transaction.end() | ||
}) | ||
}) | ||
}) | ||
|
||
// Wait for the jobs to be added to the queue and then run them | ||
function sleep(ms) { | ||
return new Promise(resolve => setTimeout(resolve, ms)); | ||
} | ||
|
||
sleep(1000).then(() => | ||
newrelic.startBackgroundTransaction('thirdTransaction', function () { | ||
const transaction = newrelic.getTransaction() | ||
queue.runJobs() | ||
transaction.end() | ||
// Finally shutdown the agent so it properly flushes all data | ||
newrelic.shutdown({ collectPendingData: true }, () => process.exit(0)) | ||
}) | ||
) | ||
} | ||
|
||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
* Copyright 2024 New Relic Corporation. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
'use strict' | ||
|
||
const newrelic = require('newrelic') | ||
const queuePath = require.resolve('./job-queue') | ||
|
||
newrelic.instrument({ | ||
// The absolute path to the required module | ||
absolutePath: queuePath, | ||
// The module's name | ||
moduleName: 'job-queue', | ||
// The function that will be called once the module is required | ||
onRequire: instrumentMyJobQueue, | ||
// The function that will be called if the instrumentation fails | ||
onError: function onError(err) { | ||
// Uh oh! Our instrumentation failed, let's see why: | ||
console.error(err.message, err.stack) | ||
|
||
// Let's kill the application when debugging so we don't miss it. | ||
process.exit(-1) | ||
} | ||
}) | ||
|
||
function instrumentMyJobQueue(shim, myModule, moduleName) { | ||
console.log(`[NEWRELIC] instrumenting ${moduleName}`) | ||
|
||
const proto = myModule.prototype; | ||
|
||
shim.record(proto, 'scheduleJob', | ||
function (shim, func, name, args) { | ||
const job = args[0]; | ||
return new shim.specs.RecorderSpec({ | ||
name: `scheduleJob - ${job.name}`, | ||
callback: shim.LAST | ||
}) | ||
} | ||
) | ||
shim.record(proto, 'runJobs', | ||
function (shim, func, name, args) { | ||
return new shim.specs.RecorderSpec({ | ||
name: 'runJobs', | ||
callback: shim.LAST | ||
}) | ||
} | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
* Copyright 2024 New Relic Corporation. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
'use strict' | ||
|
||
function Queue() { | ||
this.jobs = [] | ||
} | ||
|
||
Queue.prototype.runJobs = function run() { | ||
const jobs = this.jobs | ||
while (jobs.length) { | ||
const job = jobs.pop() | ||
job() | ||
} | ||
} | ||
|
||
Queue.prototype.scheduleJob = function scheduleJob(job) { | ||
const jobs = this.jobs | ||
process.nextTick(function () { | ||
jobs.push(job) | ||
}) | ||
} | ||
|
||
module.exports = Queue |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* Copyright 2024 New Relic Corporation. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
'use strict' | ||
|
||
/** | ||
* New Relic agent configuration. | ||
* | ||
* See lib/config/default.js in the agent distribution for a more complete | ||
* description of configuration variables and their potential values. */ | ||
|
||
exports.config = { | ||
app_name: ['Example Job Queue App'], | ||
logging: { | ||
/** | ||
* Level at which to log. 'trace' is most useful to New Relic when diagnosing | ||
* issues with the agent, 'info' and higher will impose the least overhead on | ||
* production applications. | ||
*/ | ||
level: 'trace' | ||
}, | ||
/** | ||
* When true, all request headers except for those listed in attributes.exclude | ||
* will be captured for all traces, unless otherwise specified in a destination's | ||
* attributes include/exclude lists. | ||
*/ | ||
allow_all_headers: true, | ||
attributes: { | ||
/** | ||
* Prefix of attributes to exclude from all destinations. Allows * as wildcard | ||
* at end. | ||
* | ||
* NOTE: If excluding headers, they must be in camelCase form to be filtered. | ||
* | ||
* @env NEW_RELIC_ATTRIBUTES_EXCLUDE | ||
*/ | ||
exclude: [ | ||
'request.headers.cookie', | ||
'request.headers.authorization', | ||
'request.headers.proxyAuthorization', | ||
'request.headers.setCookie*', | ||
'request.headers.x*', | ||
'response.headers.cookie', | ||
'response.headers.authorization', | ||
'response.headers.proxyAuthorization', | ||
'response.headers.setCookie*', | ||
'response.headers.x*' | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"name": "instrument-app", | ||
"version": "1.0.0", | ||
"description": "Example app instrumentating a job queue", | ||
"main": "index.js", | ||
"scripts": { | ||
"start": "node -r ./instrumentation --env-file .env index.js" | ||
}, | ||
"author": "", | ||
"license": "ISC", | ||
"dependencies": { | ||
"newrelic": "^11.19.0" | ||
}, | ||
"devDependencies": { | ||
"@newrelic/eslint-config": "^0.4.0" | ||
} | ||
} |