From af8b733ff4fb4243df681f1eeeaf5cafa21eda31 Mon Sep 17 00:00:00 2001 From: Tushar Choudhari Date: Thu, 16 Nov 2023 11:48:35 +0530 Subject: [PATCH] Add api call to generate access_token --- .gitignore | 3 ++- package-lock.json | 52 +++++++++++++++++++++++++++++++++++++++++ package.json | 2 ++ playground/app.js | 17 ++++++++------ src/OpenAPM.ts | 4 +--- src/levitate/events.ts | 53 ++++++++++++++++++++++++++++-------------- 6 files changed, 102 insertions(+), 29 deletions(-) diff --git a/.gitignore b/.gitignore index cbf5f69..9738884 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules dist .DS_Store -.idea \ No newline at end of file +.idea +.env \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 211b95a..5fe932a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "prom-client": "^14.2.0", "response-time": "^2.3.2", + "undici": "^5.27.2", "url-value-parser": "^2.2.0" }, "devDependencies": { @@ -26,6 +27,7 @@ "@typescript-eslint/parser": "^5.61.0", "@vitest/ui": "^0.34.1", "axios": "^1.4.0", + "dotenv": "^16.3.1", "eslint": "^8.44.0", "eslint-config-semistandard": "^17.0.0", "eslint-config-standard": "^17.1.0", @@ -2164,6 +2166,14 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fastify/busboy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", + "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", + "engines": { + "node": ">=14" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.13", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", @@ -4258,6 +4268,18 @@ "node": ">=6.0.0" } }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -8324,6 +8346,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici": { + "version": "5.27.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz", + "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -10123,6 +10156,11 @@ "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", "dev": true }, + "@fastify/busboy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", + "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==" + }, "@humanwhocodes/config-array": { "version": "0.11.13", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", @@ -11613,6 +11651,12 @@ "esutils": "^2.0.2" } }, + "dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -14567,6 +14611,14 @@ "which-boxed-primitive": "^1.0.2" } }, + "undici": { + "version": "5.27.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz", + "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==", + "requires": { + "@fastify/busboy": "^2.0.0" + } + }, "undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", diff --git a/package.json b/package.json index 5c0a813..f588e1a 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "@typescript-eslint/parser": "^5.61.0", "@vitest/ui": "^0.34.1", "axios": "^1.4.0", + "dotenv": "^16.3.1", "eslint": "^8.44.0", "eslint-config-semistandard": "^17.0.0", "eslint-config-standard": "^17.1.0", @@ -59,6 +60,7 @@ "dependencies": { "prom-client": "^14.2.0", "response-time": "^2.3.2", + "undici": "^5.27.2", "url-value-parser": "^2.2.0" }, "peerDependenciesMeta": { diff --git a/playground/app.js b/playground/app.js index ee33f26..49ee438 100644 --- a/playground/app.js +++ b/playground/app.js @@ -3,6 +3,7 @@ * Also, comment out the things that you are not using. For example, you can comment out the mysql code if you are * not testing or developing for the same * */ +require('dotenv').config(); var express = require('express'); var { OpenAPM } = require('../dist/index.js'); var mysql2 = require('mysql2'); @@ -15,15 +16,17 @@ const openapm = new OpenAPM({ mask: ':org' } }, + levitateConfig: { + orgSlug: process.env['LEVITATE_ORG_SLUG'], + dataSourceName: process.env['LEVITATE_DATASOURCE'], + refreshTokens: { + write: process.env['LEVITATE_WRITE_REFRESH_TOKEN'] + } + }, customPathsToMask: [/\b\d+(?:,\d+)*\b/gm], excludeDefaultLabels: ['host', 'program'] }); -openapm.on('application_started', (domainEvents) => { - console.log(domainEvents); -}); -openapm.on('application_stopped', (domainEvents) => { - console.log(domainEvents); -}); + openapm.instrument('express'); openapm.instrument('mysql'); @@ -58,6 +61,6 @@ app.get('/cancel/:ids', (req, res) => { res.status(200).json({}); }); -app.listen(3000, () => { +const server = app.listen(3000, () => { console.log('serving at 3000'); }); diff --git a/src/OpenAPM.ts b/src/OpenAPM.ts index e8ec5fa..ad3cf4f 100644 --- a/src/OpenAPM.ts +++ b/src/OpenAPM.ts @@ -81,7 +81,6 @@ export class OpenAPM extends LevitateEvents { private metricsServerPort: number; readonly environment: string; readonly program: string; - readonly levitateConfig?: LevitateConfig | undefined; private defaultLabels?: Record; private requestsCounterConfig: CounterConfiguration; private requestDurationHistogramConfig: HistogramConfiguration; @@ -94,7 +93,7 @@ export class OpenAPM extends LevitateEvents { public metricsServer?: Server; constructor(options?: OpenAPMOptions) { - super(); + super(options); // Initializing all the options this.path = options?.path ?? '/metrics'; this.metricsServerPort = options?.metricsServerPort ?? 9097; @@ -127,7 +126,6 @@ export class OpenAPM extends LevitateEvents { this.extractLabels = options?.extractLabels ?? {}; this.customPathsToMask = options?.customPathsToMask; this.excludeDefaultLabels = options?.excludeDefaultLabels; - this.levitateConfig = options?.levitateConfig; this.initiateMetricsRoute(); this.initiatePromClient(); diff --git a/src/levitate/events.ts b/src/levitate/events.ts index 4206462..500246f 100644 --- a/src/levitate/events.ts +++ b/src/levitate/events.ts @@ -1,4 +1,6 @@ import EventEmitter from 'events'; +import type { OpenAPMOptions } from '../OpenAPM'; +import { fetch, request } from 'undici'; export interface LevitateConfig { host?: string; @@ -23,9 +25,10 @@ const defaultHost = 'https://app.last9.io'; export class LevitateEvents extends EventEmitter { private eventsUrl: URL; - public levitateConfig?: LevitateConfig; - constructor() { + readonly levitateConfig?: LevitateConfig; + constructor(options?: OpenAPMOptions) { super(); + this.levitateConfig = options?.levitateConfig; this.eventsUrl = new URL( `/api/v4/organizations/${this.levitateConfig?.orgSlug}/domain_events`, this.levitateConfig?.host ?? defaultHost @@ -77,25 +80,39 @@ export class LevitateEvents extends EventEmitter { } } - private putDomainEvents(body: DomainEventsBody) { - const params = new URLSearchParams(); + private generateAccessToken = () => { + const endpoint = '/api/v4/oauth/access_token'; + const url = new URL(endpoint, this.levitateConfig?.host ?? defaultHost); + try { + return fetch(url.toString(), { + method: 'POST', + body: JSON.stringify({ + refresh_token: this.levitateConfig?.refreshTokens.write ?? '' + }) + }).then((response) => { + return response.json(); + }) as Promise<{ access_token: string }>; + } catch (error) { + console.log(error); + } + }; + + private async putDomainEvents(body: DomainEventsBody) { if (!!body) { - for (const key in body) { - if (key in body) { - params.append(key, body[key]); - } + try { + const tokenResponse = await this.generateAccessToken(); + await request(this.eventsUrl.toString(), { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + 'X-LAST9-API-TOKEN': `Bearer ${tokenResponse?.access_token}` + }, + body: JSON.stringify(body) + }); + } catch (error) { + console.log(error); } - - fetch(this.eventsUrl.toString(), { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - 'X-LAST9-API-TOKEN': `Bearer ` - }, - body: params - }); - console.log(params); } } }