Skip to content
This repository has been archived by the owner on Mar 24, 2023. It is now read-only.

Commit

Permalink
Merge pull request #62 from nervosnetwork/add-new-relic
Browse files Browse the repository at this point in the history
chore: Add new relic
  • Loading branch information
classicalliu authored Aug 27, 2021
2 parents a89a35d + e289740 commit c46fb7b
Show file tree
Hide file tree
Showing 9 changed files with 336 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ L2_SUDT_VALIDATOR_SCRIPT_TYPE_HASH=<l2 sudt validator script type hash>
TRON_ACCOUNT_LOCK_HASH=<tron account lock script hash, optional>
SENTRY_DNS=<sentry dns, optional>
SENTRY_ENVIRONMENT=<sentry environment, optional, default to `development`>,
NEW_RELIC_LICENSE_KEY=<new relic license key, optional>
EOF

$ yarn
Expand Down
2 changes: 2 additions & 0 deletions packages/api-server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
allowed-addresses.json
newrelic_agent.log
16 changes: 16 additions & 0 deletions packages/api-server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ const { wrapper } = require("./lib/ws/methods");
const expressWs = require("express-ws");
const Sentry = require("@sentry/node");

NEW_RELIC_LICENSE_KEY = process.env.NEW_RELIC_LICENSE_KEY;

let newrelic = undefined;
if (NEW_RELIC_LICENSE_KEY) {
console.log("new relic init !!!");
newrelic = require("newrelic");
}

const app = express();

app.use(express.json());
Expand Down Expand Up @@ -50,6 +58,14 @@ app.use(cors(corsOptions));
app.use(express.urlencoded({ extended: false }));

app.use(function (req, _res, next) {
if (NEW_RELIC_LICENSE_KEY) {
// set new relic name
const transactionName = `${req.method} ${req.url}#${req.body.method}`;
console.log("#transactionName:", transactionName);
newrelic.setTransactionName(transactionName);
}

// log request method / body
if (process.env.WEB3_LOG_REQUEST_BODY) {
console.log("request.body:", req.body);
} else {
Expand Down
72 changes: 72 additions & 0 deletions packages/api-server/newrelic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
'use strict'

require("dotenv").config({ path: "./.env" });

/**
* 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 = {
/**
* Array of application names.
*/
app_name: ['Godwoken Web3'],
/**
* Your New Relic license key.
*/
license_key: process.env.NEW_RELIC_LICENSE_KEY,
/**
* This setting controls distributed tracing.
* Distributed tracing lets you see the path that a request takes through your
* distributed system. Enabling distributed tracing changes the behavior of some
* New Relic features, so carefully consult the transition guide before you enable
* this feature: https://docs.newrelic.com/docs/transition-guide-distributed-tracing
* Default is false.
*/
distributed_tracing: {
/**
* Enables/disables distributed tracing.
*
* @env NEW_RELIC_DISTRIBUTED_TRACING_ENABLED
*/
enabled: true
},
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: 'info'
},
/**
* 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*'
]
}
}
3 changes: 3 additions & 0 deletions packages/api-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"dependencies": {
"@ckb-lumos/base": "^0.16.0",
"@godwoken-web3/godwoken": "0.6.0-rc5",
"@newrelic/native-metrics": "^7.0.1",
"@polyjuice-provider/base": "^0.0.1-rc7",
"@sentry/node": "^6.11.0",
"blake2b": "2.1.3",
Expand All @@ -35,13 +36,15 @@
"leveldown": "^6.0.1",
"levelup": "^5.0.1",
"morgan": "~1.9.1",
"newrelic": "^8.1.0",
"pg": "^8.5.1",
"rlp": "^2.2.6",
"secp256k1": "^4.0.2"
},
"devDependencies": {
"@types/leveldown": "^4.0.3",
"@types/levelup": "^4.3.3",
"@types/newrelic": "^7.0.2",
"@types/secp256k1": "^4.0.2",
"ava": "^3.15.0",
"concurrently": "^6.0.0",
Expand Down
1 change: 1 addition & 0 deletions packages/api-server/src/base/env-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const envConfig = {
polyjuiceValidatorTypeHash: getOptional("POLYJUICE_VALIDATOR_TYPE_HASH"),
rollupConfigHash: getOptional("ROLLUP_CONFIG_HASH"),
tronAccountLockHash: getOptional("TRON_ACCOUNT_LOCK_HASH"),
newRelicLicenseKey: getOptional("NEW_RELIC_LICENSE_KEY"),
};

function getRequired(name: string): string {
Expand Down
31 changes: 31 additions & 0 deletions packages/api-server/src/block-emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import { Query } from "./db";
import { EventEmitter } from "events";
import { toApiNewHead } from "./db/types";

let newrelic: any = undefined;
if (envConfig.newRelicLicenseKey) {
newrelic = require("newrelic");
}

export class BlockEmitter {
private query: Query;
private isRunning: boolean;
Expand Down Expand Up @@ -62,6 +67,32 @@ export class BlockEmitter {
return timeout;
}

// add new relic background transaction
if (envConfig.newRelicLicenseKey) {
return newrelic.startBackgroundTransaction(
`BlockEmitter#pool`,
async () => {
newrelic.getTransaction();
try {
const min = this.currentTip;
const max = tip;
const blocks = await this.query.getBlocksByNumbers(min, max);
const newHeads = blocks.map((b) => toApiNewHead(b));
this.emitter.emit("newHeads", newHeads);
const logs = await this.query.getLogs({}, min + BigInt(1), max); // exclude min & include max;
this.emitter.emit("logs", logs);
this.currentTip = tip;

return timeout;
} catch (error) {
throw error;
} finally {
newrelic.endTransaction();
}
}
);
}

const min = this.currentTip;
const max = tip;
const blocks = await this.query.getBlocksByNumbers(min, max);
Expand Down
22 changes: 22 additions & 0 deletions packages/api-server/src/ws/methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import crypto from "crypto";
import { HexNumber } from "@ckb-lumos/base";
import { Log, LogQueryOption, toApiLog } from "../db/types";
import { filterLogsByAddress, filterLogsByTopics } from "../db";
import { envConfig } from "../base/env-config";

let newrelic: any = undefined;
if (envConfig.newRelicLicenseKey) {
newrelic = require("newrelic");
}

const blockEmitter = new BlockEmitter();
blockEmitter.start();
Expand All @@ -18,6 +24,22 @@ export function wrapper(ws: any, _req: any) {

for (const [key, value] of Object.entries(methods)) {
ws.on(key, function (...args: any[]) {
// add web transaction for websocket request
if (envConfig.newRelicLicenseKey) {
return newrelic.startWebTransaction(`/ws#${key}`, async () => {
newrelic.getTransaction();
try {
const params = args.slice(0, args.length - 1);
const cb = args[args.length - 1];
(value as any)(params, cb);
} catch (error) {
throw error;
} finally {
newrelic.endTransaction();
}
});
}

const params = args.slice(0, args.length - 1);
const cb = args[args.length - 1];
(value as any)(params, cb);
Expand Down
Loading

0 comments on commit c46fb7b

Please sign in to comment.