From d85592b5f3a0dbcf315b1e1336181c0927cba9f4 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Tue, 15 Jun 2021 19:10:38 -0700 Subject: [PATCH] feat: DataDog metrics (#2228) * wip * chore: Change event names, add additional events * fix: Not counting connect events --- package.json | 1 + server/main.js | 25 +++++++++++++++++-- server/utils/metrics.js | 26 ++++++++++++++++++++ yarn.lock | 53 ++++++++++++++++++++++++++++++++--------- 4 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 server/utils/metrics.js diff --git a/package.json b/package.json index c10e024f..79d2ba97 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,7 @@ "compressorjs": "^1.0.7", "copy-to-clipboard": "^3.3.1", "core-js": "^3.10.2", + "datadog-metrics": "^0.9.3", "date-fns": "2.22.1", "dd-trace": "^0.32.2", "debug": "^4.1.1", diff --git a/server/main.js b/server/main.js index dfa1e6c9..462ece7f 100644 --- a/server/main.js +++ b/server/main.js @@ -9,6 +9,7 @@ import { Document, Collection, View } from "./models"; import policy from "./policies"; import { client, subscriber } from "./redis"; import { getUserForJWT } from "./utils/jwt"; +import * as metrics from "./utils/metrics"; import { checkMigrations } from "./utils/startup"; const server = http.createServer(app.callback()); @@ -38,6 +39,16 @@ io.of("/").adapter.on("error", (err) => { } }); +io.on("connection", (socket) => { + metrics.increment("websockets.connected"); + metrics.gauge("websockets.count", socket.client.conn.server.clientsCount); + + socket.on("disconnect", () => { + metrics.increment("websockets.disconnected"); + metrics.gauge("websockets.count", socket.client.conn.server.clientsCount); + }); +}); + SocketAuth(io, { authenticate: async (socket, data, callback) => { const { token } = data; @@ -83,7 +94,9 @@ SocketAuth(io, { }).findByPk(event.collectionId); if (can(user, "read", collection)) { - socket.join(`collection-${event.collectionId}`); + socket.join(`collection-${event.collectionId}`, () => { + metrics.increment("websockets.collections.join"); + }); } } @@ -103,6 +116,8 @@ SocketAuth(io, { ); socket.join(room, () => { + metrics.increment("websockets.documents.join"); + // let everyone else in the room know that a new user joined io.to(room).emit("user.join", { userId: user.id, @@ -146,11 +161,15 @@ SocketAuth(io, { // allow the client to request to leave rooms socket.on("leave", (event) => { if (event.collectionId) { - socket.leave(`collection-${event.collectionId}`); + socket.leave(`collection-${event.collectionId}`, () => { + metrics.increment("websockets.collections.leave"); + }); } if (event.documentId) { const room = `document-${event.documentId}`; socket.leave(room, () => { + metrics.increment("websockets.documents.leave"); + io.to(room).emit("user.leave", { userId: user.id, documentId: event.documentId, @@ -174,6 +193,8 @@ SocketAuth(io, { }); socket.on("presence", async (event) => { + metrics.increment("websockets.presence"); + const room = `document-${event.documentId}`; if (event.documentId && socket.rooms[room]) { diff --git a/server/utils/metrics.js b/server/utils/metrics.js new file mode 100644 index 00000000..8518d7fe --- /dev/null +++ b/server/utils/metrics.js @@ -0,0 +1,26 @@ +// @flow +import metrics from "datadog-metrics"; + +if (process.env.DD_API_KEY) { + metrics.init({ + apiKey: process.env.DD_API_KEY, + prefix: "outline.", + defaultTags: [`env:${process.env.DD_ENV || process.env.NODE_ENV}`], + }); +} + +export function gauge(key: string, value: number): void { + if (!process.env.DD_API_KEY) { + return; + } + + return metrics.gauge(key, value); +} + +export function increment(key: string, tags?: { [string]: string }): void { + if (!process.env.DD_API_KEY) { + return; + } + + return metrics.increment(key, tags); +} diff --git a/yarn.lock b/yarn.lock index 080235a0..994a78f4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1009,7 +1009,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.12.5", "@babel/types@^7.14.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0": +"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.12.1", "@babel/types@^7.12.5", "@babel/types@^7.14.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.5.tgz#3bb997ba829a2104cedb20689c4a5b8121d383ff" integrity sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg== @@ -3120,6 +3120,11 @@ big.js@^5.2.2: resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== +bignumber.js@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5" + integrity sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA== + binary-extensions@^1.0.0: version "1.13.1" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" @@ -4445,6 +4450,14 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +datadog-metrics@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/datadog-metrics/-/datadog-metrics-0.9.3.tgz#e62d92b9619129805802d82111c8bcc4439fc859" + integrity sha512-BVsBX2t+4yA3tHs7DnB5H01cHVNiGJ/bHA8y6JppJDyXG7s2DLm6JaozPGpgsgVGd42Is1CHRG/yMDQpt877Xg== + dependencies: + debug "3.1.0" + dogapi "2.8.4" + date-fns@2.22.1: version "2.22.1" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.22.1.tgz#1e5af959831ebb1d82992bf67b765052d8f0efc4" @@ -4492,6 +4505,13 @@ debug@*, debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: dependencies: ms "2.1.2" +debug@3.1.0, debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.1, debug@^2.6.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -4506,13 +4526,6 @@ debug@^3.1.0, debug@^3.2.6: dependencies: ms "^2.1.1" -debug@~3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - debug@~4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" @@ -4722,6 +4735,17 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dogapi@2.8.4: + version "2.8.4" + resolved "https://registry.yarnpkg.com/dogapi/-/dogapi-2.8.4.tgz#ada64f20c6acdea206b9fd9e70df0c96241b6621" + integrity sha512-065fsvu5dB0o4+ENtLjZILvXMClDNH/yA9H6L8nsdcNiz9l0Hzpn7aQaCOPYXxqyzq4CRPOdwkFXUjDOXfRGbg== + dependencies: + extend "^3.0.2" + json-bigint "^1.0.0" + lodash "^4.17.21" + minimist "^1.2.5" + rc "^1.2.8" + dom-converter@^0.2: version "0.2.0" resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" @@ -5556,7 +5580,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@^3.0.0, extend@~3.0.2: +extend@^3.0.0, extend@^3.0.2, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -7824,6 +7848,13 @@ jsesc@~0.5.0: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= +json-bigint@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1" + integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ== + dependencies: + bignumber.js "^9.0.0" + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -8591,7 +8622,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.0.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5: +lodash@^4.0.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -10594,7 +10625,7 @@ raw-loader@^0.5.1: resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" integrity sha1-DD0L6u2KAclm2Xh793goElKpeao= -rc@^1.0.1, rc@^1.1.6: +rc@^1.0.1, rc@^1.1.6, rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==