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

Add IP metrics to REST #2174

Merged
merged 17 commits into from
Jun 28, 2021
23 changes: 23 additions & 0 deletions hedera-mirror-rest/__tests__/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -733,3 +733,26 @@ describe('utils validateReq', () => {
});
});
});

describe('Utils ipMask tests', () => {
test('Verify ipV4', () => {
const maskedIp = utils.ipMask('12.214.31.144');
expect(maskedIp).toStrictEqual('12.214.31.0');
});
test('Verify ipV6', () => {
const maskedIp = utils.ipMask('2001:0db8:85a3:a13c:0000:8a2e:0370:7334');
expect(maskedIp).toStrictEqual('2001:db8:85a3::');
});
test('Verify ipV6 short form back', () => {
const maskedIp = utils.ipMask('1::');
expect(maskedIp).toStrictEqual('1::');
});
test('Verify ipV6 short form front', () => {
const maskedIp = utils.ipMask('::ffff');
expect(maskedIp).toStrictEqual('::');
});
test('Verify ipV6 dual', () => {
const maskedIp = utils.ipMask('2001:db8:3333:4444:5555:6666:1.2.3.4');
expect(maskedIp).toStrictEqual('2001:db8:3333::0.0.0.0');
});
Comment on lines +737 to +757
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These IPs were taken from examples for the library, some made up, none are sensitive.

});
1 change: 1 addition & 0 deletions hedera-mirror-rest/config/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ hedera:
password: password
username: metrics
uriPath: '/swagger'
ipMetrics: false
openapi:
specFileName: 'openapi'
swaggerUIPath: 'docs'
Expand Down
17 changes: 17 additions & 0 deletions hedera-mirror-rest/middleware/metricsHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@

// ext libraries
const extend = require('extend');
const client = require('prom-client');
const swStats = require('swagger-stats');

// files
const config = require('../config');
const oasHandler = require('./openapiHandler');
const {ipMask} = require('../utils');

const metricsHandler = () => {
const defaultMetricsConfig = {
Expand All @@ -52,6 +54,21 @@ const onMetricsAuthenticate = async (req, username, password) => {
});
};

const ipEndpointHistogram = new client.Counter({
name: 'hedera_mirror_rest_request_count',
help: 'a counter mapping ip addresses to the endpoints they hit',
labelNames: ['endpoint', 'ip'],
});

const recordIpAndEndpoint = async (req, res, next) => {
if (req.route !== undefined) {
ipEndpointHistogram.labels(req.route.path, ipMask(req.ip)).inc();
}
};

const maskIp = (ip) => {};
steven-sheehy marked this conversation as resolved.
Show resolved Hide resolved

module.exports = {
metricsHandler,
recordIpAndEndpoint,
};
1 change: 1 addition & 0 deletions hedera-mirror-rest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-security": "^1.4.0",
"husky": "^6.0.0",
"ip-anonymize": "^0.1.0",
"jest": "^27.0.4",
"jest-circus": "^27.0.4",
"jest-junit": "^12.2.0",
Expand Down
7 changes: 6 additions & 1 deletion hedera-mirror-rest/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const tokens = require('./tokens');
const topicmessage = require('./topicmessage');
const transactions = require('./transactions');
const {handleError} = require('./middleware/httpErrorHandler');
const {metricsHandler} = require('./middleware/metricsHandler');
const {metricsHandler, recordIpAndEndpoint} = require('./middleware/metricsHandler');
const {serveSwaggerDocs} = require('./middleware/openapiHandler');
const {responseHandler} = require('./middleware/responseHandler');
const {requestLogger, requestQueryParser} = require('./middleware/requestHandler');
Expand Down Expand Up @@ -165,6 +165,11 @@ app.getAsync(`${apiPrefix}/schedules/:id`, schedules.getScheduleById);
app.getAsync(`${apiPrefix}/transactions`, transactions.getTransactions);
app.getAsync(`${apiPrefix}/transactions/:id`, transactions.getOneTransaction);

// record ip metrics if enabled
if (config.metrics.ipMetrics) {
app.useAsync(recordIpAndEndpoint);
Nana-EC marked this conversation as resolved.
Show resolved Hide resolved
}

// response data handling middleware
app.useAsync(responseHandler);

Expand Down
11 changes: 11 additions & 0 deletions hedera-mirror-rest/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

const _ = require('lodash');
const crypto = require('crypto');
const anonymize = require('ip-anonymize');
const math = require('mathjs');
const constants = require('./constants');
const EntityId = require('./entityId');
Expand Down Expand Up @@ -880,6 +881,15 @@ const queryQuietly = async (query, ...params) => {
}
};

/**
* Masks the given IP based on Google Analytics standards
* @param {String} ip the IP address from the req object.
* @returns {String} The masked IP address
*/
const ipMask = (ip) => {
return anonymize(ip, 24, 48);
};

module.exports = {
buildFilterObject,
buildComparatorFilter,
Expand All @@ -898,6 +908,7 @@ module.exports = {
getNullableNumber,
getPaginationLink,
getTransactionTypeQuery,
ipMask,
isRepeatedQueryParameterValidLength,
isTestEnv,
isValidPublicKeyQuery,
Expand Down