Skip to content

Commit

Permalink
DPLT-1044 Expose context method for writing custom Grafana metrics (#126
Browse files Browse the repository at this point in the history
)
  • Loading branch information
morgsmccauley authored Jul 16, 2023
1 parent e9b66cc commit 5a026f3
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 9 deletions.
4 changes: 4 additions & 0 deletions indexer-js-queue-handler/__snapshots__/metrics.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ exports[`Metrics writes the block height for an indexer function 1`] = `
"Name": "STAGE",
"Value": "dev",
},
{
"Name": "HISTORICAL",
"Value": false,
},
],
"MetricName": "INDEXER_FUNCTION_LATEST_BLOCK_HEIGHT",
"Unit": "None",
Expand Down
18 changes: 14 additions & 4 deletions indexer-js-queue-handler/indexer.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default class Indexer {
functionSubsegment.addAnnotation('indexer_function', function_name);
simultaneousPromises.push(this.writeLog(function_name, block_height, runningMessage));

simultaneousPromises.push(this.deps.metrics.putBlockHeight(indexerFunction.account_id, indexerFunction.function_name, block_height));
simultaneousPromises.push(this.deps.metrics.putBlockHeight(indexerFunction.account_id, indexerFunction.function_name, is_historical, block_height));

const hasuraRoleName = function_name.split('/')[0].replace(/[.-]/g, '_');
const functionNameWithoutAccount = function_name.split('/')[1].replace(/[.-]/g, '_');
Expand Down Expand Up @@ -74,7 +74,7 @@ export default class Indexer {
const vm = new VM({timeout: 3000, allowAsync: true});
const mutationsReturnValue = {mutations: [], variables: {}, keysValues: {}};
const context = options.imperative
? this.buildImperativeContextForFunction(function_name, functionNameWithoutAccount, block_height, hasuraRoleName)
? this.buildImperativeContextForFunction(function_name, functionNameWithoutAccount, block_height, hasuraRoleName, is_historical)
: this.buildFunctionalContextForFunction(mutationsReturnValue, function_name, block_height);

vm.freeze(blockWithHelpers, 'block');
Expand Down Expand Up @@ -225,7 +225,7 @@ export default class Indexer {
};
}

buildImperativeContextForFunction(functionName, functionNameWithoutAccount, block_height, hasuraRoleName) {
buildImperativeContextForFunction(functionName, functionNameWithoutAccount, block_height, hasuraRoleName, is_historical) {
return {
graphql: async (operation, variables) => {
try {
Expand Down Expand Up @@ -254,7 +254,17 @@ export default class Indexer {
},
log: async (log) => {
return await this.writeLog(functionName, block_height, log);
}
},
putMetric: (name, value) => {
const [accountId, fnName] = functionName.split('/');
return this.deps.metrics.putCustomMetric(
accountId,
fnName,
is_historical,
`CUSTOM_${name}`,
value
);
},
};
}

Expand Down
45 changes: 44 additions & 1 deletion indexer-js-queue-handler/indexer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ mutation _1 { set(functionName: "buildnear.testnet/test", key: "foo2", data: "in
};
await indexer.runFunctions(block_height, functions, false);

expect(metrics.putBlockHeight).toHaveBeenCalledWith('buildnear.testnet', 'test', block_height);
expect(metrics.putBlockHeight).toHaveBeenCalledWith('buildnear.testnet', 'test', false, block_height);
});

test('does not attach the hasura admin secret header when no role specified', async () => {
Expand Down Expand Up @@ -895,6 +895,49 @@ mutation _1 { set(functionName: "buildnear.testnet/test", key: "foo2", data: "in
]);
});

test('allows writing of custom metrics', async () => {
const mockFetch = jest.fn(() => ({
status: 200,
json: async () => ({
errors: null,
}),
}));
const block_height = 456;
const mockS3 = {
getObject: jest.fn(() => ({
promise: () => Promise.resolve({
Body: {
toString: () => JSON.stringify({
chunks: [],
header: {
height: block_height
}
})
}
})
})),
};
const metrics = {
putBlockHeight: () => {},
putCustomMetric: jest.fn(),
};
const indexer = new Indexer('mainnet', { fetch: mockFetch, s3: mockS3, awsXray: mockAwsXray, metrics });

const functions = {};
functions['buildnear.testnet/test'] = {code:`
context.putMetric('TEST_METRIC', 1)
`};
await indexer.runFunctions(block_height, functions, true, { imperative: true });

expect(metrics.putCustomMetric).toHaveBeenCalledWith(
'buildnear.testnet',
'test',
true,
'CUSTOM_TEST_METRIC',
1
);
});

// The unhandled promise causes problems with test reporting.
// Note unhandled promise rejections fail to proceed to the next function on AWS Lambda
test.skip('Indexer.runFunctions() continues despite promise rejection, unable to log rejection', async () => {
Expand Down
14 changes: 11 additions & 3 deletions indexer-js-queue-handler/metrics.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ export default class Metrics {
this.namespace = namespace;
}

putBlockHeight(accountId, functionName, height) {
putBlockHeight(accountId, functionName, isHistorical, height) {
return this.putCustomMetric(accountId, functionName, isHistorical, "INDEXER_FUNCTION_LATEST_BLOCK_HEIGHT", height);
}

putCustomMetric(accountId, functionName, isHistorical, metricName, value) {
return this.cloudwatch
.putMetricData({
MetricData: [
{
MetricName: "INDEXER_FUNCTION_LATEST_BLOCK_HEIGHT",
MetricName: metricName,
Dimensions: [
{
Name: "ACCOUNT_ID",
Expand All @@ -26,9 +30,13 @@ export default class Metrics {
Name: "STAGE",
Value: process.env.STAGE,
},
{
Name: "HISTORICAL",
Value: isHistorical,
},
],
Unit: "None",
Value: height,
Value: value,
},
],
Namespace: this.namespace,
Expand Down
2 changes: 1 addition & 1 deletion indexer-js-queue-handler/metrics.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('Metrics', () => {
};
const metrics = new Metrics('test', cloudwatch);

await metrics.putBlockHeight('morgs.near', 'test', 2);
await metrics.putBlockHeight('morgs.near', 'test', false, 2);

expect(cloudwatch.putMetricData).toBeCalledTimes(1);
expect(cloudwatch.putMetricData.mock.calls[0]).toMatchSnapshot()
Expand Down

0 comments on commit 5a026f3

Please sign in to comment.