diff --git a/index.js b/index.js index 2d33505..6366a01 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ import express from "express"; import expressPromiseRouter from "express-promise-router"; import config from "exp-config"; +import assert from "assert"; import { init } from "./lib/recipe-repo.js"; import buildLogger from "./lib/logger.js"; @@ -17,6 +18,9 @@ export function route(key, fn) { } export function start({ recipes, triggers, startServer = true }) { + + assert(config.appName, "appName must be set in config"); + const router = expressPromiseRouter(); const app = express(); app.use(express.json()); diff --git a/lib/message-handler.js b/lib/message-handler.js index 8c18749..b891452 100644 --- a/lib/message-handler.js +++ b/lib/message-handler.js @@ -5,6 +5,7 @@ import publishMessage, { rejectMessage } from "./publish-message.js"; import resumeMessage from "./resume-message.js"; import buildContext from "./context.js"; import jobStorage from "./job-storage/index.js"; +import metrics from "./metrics.js"; const maxResumeCount = config.maxResumeCount || 10; @@ -40,6 +41,9 @@ export default async function messageHandler(recipeMap, req, res) { logger.error(`Got message without key ${messageId}`); return res.status(400).send(); } + + metrics.messages.inc(); + logger.info(`incoming message ${JSON.stringify(messageData)}`); const parts = key.split("."); const suffix = parts.pop(); @@ -89,6 +93,7 @@ export default async function messageHandler(recipeMap, req, res) { try { const result = await unrecoverableHandler(message, context); const data = appendData(message.data, result); + metrics.unrecoverableMessages.inc(); await publishMessage({ ...message, data }, { key: `${key}.processed`, correlationId, parentCorrelationId }); } catch (err) { return res.status(500).send(); @@ -109,6 +114,7 @@ export default async function messageHandler(recipeMap, req, res) { // TODO: should we delete the job that was stored here } } + metrics.processedSequences.inc(); return res.status(200).send(); } @@ -163,10 +169,12 @@ export default async function messageHandler(recipeMap, req, res) { if (error.rejected) { logger.error(`Rejected message with correlationId: ${correlationId}. Error: ${error}. Message: ${message}`); await rejectMessage({ ...message, error: { message: error.extraMessage } }, { key }); + metrics.rejectedMessages.inc(); return res.status(200).send(); } if (error.retry) { logger.info(`Retrying message ${messageId}`); + metrics.retriedMessages.inc(); return res.status(400).send(); } if (error.unrecoverable) { diff --git a/lib/metrics.js b/lib/metrics.js new file mode 100644 index 0000000..3e57448 --- /dev/null +++ b/lib/metrics.js @@ -0,0 +1,36 @@ +import config from "exp-config"; +import { pushClient, cloudRunResourceProvider } from "@bonniernews/gcp-push-metrics"; + +import buildLogger from "./logger.js"; + +const client = pushClient({ logger: buildLogger(), resourceProvider: cloudRunResourceProvider }); +const { appName } = config; + +const labels = { + bnNamespace: [], + appName: [], + path: [], +}; + +export default { + messages: client.counter({ + name: `lu_${appName}_messages`, + ...labels, + }), + rejectedMessages: client.counter({ + name: `lu_${appName}_rejected`, + ...labels, + }), + retriedMessages: client.counter({ + name: `lu_${appName}_retried`, + ...labels, + }), + unrecoverableMessages: client.counter({ + name: `lu_${appName}_unrecoverable`, + ...labels, + }), + processedSequences: client.counter({ + name: `lu_${appName}_processed`, + ...labels, + }), +}; diff --git a/package-lock.json b/package-lock.json index fc86545..8d7cbed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,15 @@ { "name": "@bonniernews/b0rker", - "version": "4.3.1", + "version": "4.3.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bonniernews/b0rker", - "version": "4.3.1", + "version": "4.3.2", "license": "MIT", "dependencies": { + "@bonniernews/gcp-push-metrics": "^3.1.0", "@google-cloud/firestore": "^6.4.1", "@google-cloud/pubsub": "^3.2.1", "@google-cloud/tasks": "^3.0.5", @@ -223,6 +224,14 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@bonniernews/gcp-push-metrics": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@bonniernews/gcp-push-metrics/-/gcp-push-metrics-3.1.0.tgz", + "integrity": "sha512-OQFb8TeHNklyzmxMZVIz/5+2T7EbCgDUqP3hAdNETALS7jWEaH0MLfXeBe7z4rDLEkvhofNj3J2+gSGVIYnXSQ==", + "dependencies": { + "@google-cloud/monitoring": "^2.3.5" + } + }, "node_modules/@bonniernews/lu-test": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/@bonniernews/lu-test/-/lu-test-4.1.1.tgz", @@ -460,6 +469,17 @@ "node": ">=12.0.0" } }, + "node_modules/@google-cloud/monitoring": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@google-cloud/monitoring/-/monitoring-2.3.5.tgz", + "integrity": "sha512-91+gobJMXEibKxnPOY3Q+ccFifQyRUdFpQ8uQ8acqWesxVj9ZH1VRm3ZpoleYWbbMe32cymhpGRamZ6t31veRQ==", + "dependencies": { + "google-gax": "^2.24.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@google-cloud/paginator": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-4.0.1.tgz", @@ -1821,7 +1841,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -7719,7 +7738,6 @@ "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -7737,7 +7755,6 @@ "version": "20.2.9", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, "engines": { "node": ">=10" } diff --git a/package.json b/package.json index 5af0d76..9a217b3 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "google-auth-library": "^8.7.0", "joi": "^17.7.0", "pino": "^8.7.0", - "uuid": "^9.0.0" + "uuid": "^9.0.0", + "@bonniernews/gcp-push-metrics": "^3.1.0" }, "devDependencies": { "@bonniernews/lu-test": "^4.0.0", @@ -57,6 +58,9 @@ "lib": "lib", "test": "test" }, + "overrides": { + "google-gax@<3.6.1": "^3.6.1" + }, "keywords": [ "pubsub" ],