Opentelemetry metrics API (#72)

* Opentelemetry metrics API

* Rename the counter

* Add metrics API

* Add Otl to Nextjs

* Add otel protocol

* Fix the port

* Fix the port

* Fix

* Fix

* Fix

* fixed default postgres url

* tweaks to metrics name and attributes

Co-authored-by: Kiran K <kiran@Kirans-MacBook-Pro.local>
Co-authored-by: Deepak Prabhakara <deepak@boxyhq.com>
This commit is contained in:
Kiran K 2022-02-16 05:04:12 +05:30 committed by GitHub
parent 99ef761f46
commit 78782fbbb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 310 additions and 7 deletions

View File

@ -7,9 +7,13 @@ CLIENT_SECRET_VERIFIER=
# Database settings
DB_ENGINE=sql
DB_URL=postgres://postgres:postgres@localhost:5450/jackson
DB_URL=postgres://postgres:postgres@localhost:5450/postgres
DB_TYPE=postgres
DB_TTL=300
DB_CLEANUP_LIMIT=1000
# You can use openssl to generate a random 32 character key: openssl rand -base64 24
DB_ENCRYPTION_KEY=
# OpenTelemetry
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=
OTEL_EXPORTER_OTLP_HEADERS=

View File

@ -1,5 +1,6 @@
import jackson, { IAPIController, IOAuthController } from '@boxyhq/saml-jackson';
import env from '@lib/env';
import '@lib/metrics';
let apiController: IAPIController;
let oauthController: IOAuthController;

16
lib/metrics.ts Normal file
View File

@ -0,0 +1,16 @@
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
import { MeterProvider } from '@opentelemetry/sdk-metrics-base';
import { metrics } from '@opentelemetry/api-metrics';
import { Resource } from '@opentelemetry/resources';
import packageInfo from '../package.json';
const meterProvider = new MeterProvider({
exporter: new OTLPMetricExporter(),
interval: 1000,
resource: new Resource({
'service.name': `${packageInfo.name}`,
'service.version': `${packageInfo.version}`,
}),
});
metrics.setGlobalMeterProvider(meterProvider);

14
npm/package-lock.json generated
View File

@ -10,6 +10,7 @@
"license": "Apache 2.0",
"dependencies": {
"@boxyhq/saml20": "0.2.0",
"@opentelemetry/api-metrics": "^0.27.0",
"@peculiar/webcrypto": "1.2.3",
"@peculiar/x509": "1.6.1",
"cors": "2.8.5",
@ -766,6 +767,14 @@
"node": ">= 8"
}
},
"node_modules/@opentelemetry/api-metrics": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/api-metrics/-/api-metrics-0.27.0.tgz",
"integrity": "sha512-tB79288bwjkdhPNpw4UdOEy3bacVwtol6Que7cAu8KEJ9ULjRfSiwpYEwJY/oER3xZ7zNFz0uiJ7N1jSiotpVA==",
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/@peculiar/asn1-cms": {
"version": "2.0.44",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.0.44.tgz",
@ -8815,6 +8824,11 @@
"fastq": "^1.6.0"
}
},
"@opentelemetry/api-metrics": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/api-metrics/-/api-metrics-0.27.0.tgz",
"integrity": "sha512-tB79288bwjkdhPNpw4UdOEy3bacVwtol6Que7cAu8KEJ9ULjRfSiwpYEwJY/oER3xZ7zNFz0uiJ7N1jSiotpVA=="
},
"@peculiar/asn1-cms": {
"version": "2.0.44",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.0.44.tgz",

View File

@ -37,6 +37,7 @@
},
"dependencies": {
"@boxyhq/saml20": "0.2.0",
"@opentelemetry/api-metrics": "0.27.0",
"@peculiar/webcrypto": "1.2.3",
"@peculiar/x509": "1.6.1",
"cors": "2.8.5",

View File

@ -1,5 +1,6 @@
import crypto from 'crypto';
import * as dbutils from '../db/utils';
import * as metrics from '../opentelemetry/metrics';
import saml from '../saml/saml';
import x509 from '../saml/x509';
import { IAPIController, IdPConfig, OAuth, Storable } from '../typings';
@ -101,6 +102,8 @@ export class APIController implements IAPIController {
public async config(body: IdPConfig): Promise<OAuth> {
const { encodedRawMetadata, rawMetadata, defaultRedirectUrl, redirectUrl, tenant, product } = body;
metrics.increment('createConfig');
this._validateIdPConfig(body);
let metaData = rawMetadata;
@ -211,6 +214,8 @@ export class APIController implements IAPIController {
}): Promise<Partial<OAuth>> {
const { clientID, tenant, product } = body;
metrics.increment('getConfig');
if (clientID) {
const samlConfig = await this.configStore.get(clientID);
@ -278,6 +283,8 @@ export class APIController implements IAPIController {
}): Promise<void> {
const { clientID, clientSecret, tenant, product } = body;
metrics.increment('deleteConfig');
if (clientID && clientSecret) {
const samlConfig = await this.configStore.get(clientID);

View File

@ -1,5 +1,8 @@
import crypto from 'crypto';
import { promisify } from 'util';
import { deflateRaw } from 'zlib';
import * as dbutils from '../db/utils';
import * as metrics from '../opentelemetry/metrics';
import saml from '../saml/saml';
import {
IOAuthController,
@ -16,8 +19,6 @@ import * as allowed from './oauth/allowed';
import * as codeVerifier from './oauth/code-verifier';
import * as redirect from './oauth/redirect';
import { IndexNames } from './utils';
import { promisify } from 'util';
import { deflateRaw } from 'zlib';
const deflateRawAsync = promisify(deflateRaw);
@ -70,6 +71,8 @@ export class OAuthController implements IOAuthController {
provider = 'saml',
} = body;
metrics.increment('oauthAuthorize');
if (!redirect_uri) {
throw new JacksonError('Please specify a redirect URL.', 400);
}
@ -299,6 +302,8 @@ export class OAuthController implements IOAuthController {
public async token(body: OAuthTokenReq): Promise<OAuthTokenRes> {
const { client_id, client_secret, code_verifier, code, grant_type = 'authorization_code' } = body;
metrics.increment('oauthToken');
if (grant_type !== 'authorization_code') {
throw new JacksonError('Unsupported grant_type', 400);
}
@ -386,6 +391,8 @@ export class OAuthController implements IOAuthController {
public async userInfo(token: string): Promise<Profile> {
const rsp = await this.tokenStore.get(token);
metrics.increment('oauthUserInfo');
if (!rsp || !rsp.claims) {
throw new JacksonError('Invalid token', 403);
}

View File

@ -1,8 +1,8 @@
import { JacksonOption } from './typings';
import { APIController } from './controller/api';
import { OAuthController } from './controller/oauth';
import DB from './db/db';
import readConfig from './read-config';
import { JacksonOption } from './typings';
const defaultOpts = (opts: JacksonOption): JacksonOption => {
const newOpts = {

View File

@ -0,0 +1,50 @@
import { metrics } from '@opentelemetry/api-metrics';
const counters = {
createConfig: {
name: 'jackson.config.create',
description: 'Number of SAML config create requests',
},
getConfig: {
name: 'jackson.config.get',
description: 'Number of SAML config get requests',
},
deleteConfig: {
name: 'jackson.config.delete',
description: 'Number of SAML config delete requests',
},
oauthAuthorize: {
name: 'jackson.oauth.authorize',
description: 'Number of SAML oauth authorize requests',
},
oauthToken: {
name: 'jackson.oauth.token',
description: 'Number of SAML oauth token requests',
},
oauthUserInfo: {
name: 'jackson.oauth.userinfo',
description: 'Number of SAML oauth user info requests',
},
};
const createCounter = (action: string) => {
const meter = metrics.getMeterProvider().getMeter('jackson');
const counter = counters[action];
return meter.createCounter(counter.name, {
description: counter.description,
});
};
const increment = (action: string) => {
const counter = createCounter(action);
counter.add(1, { provider: 'saml' });
};
export { increment };

206
package-lock.json generated
View File

@ -10,6 +10,9 @@
"license": "Apache 2.0",
"dependencies": {
"@boxyhq/saml-jackson": "file:./npm",
"@opentelemetry/api-metrics": "0.27.0",
"@opentelemetry/exporter-metrics-otlp-http": "0.27.0",
"@opentelemetry/sdk-metrics-base": "0.27.0",
"cors": "2.8.5",
"next": "12.0.10",
"react": "17.0.2",
@ -1253,6 +1256,127 @@
"node": ">= 8"
}
},
"node_modules/@opentelemetry/api": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.0.4.tgz",
"integrity": "sha512-BuJuXRSJNQ3QoKA6GWWDyuLpOUck+9hAXNMCnrloc1aWVoy6Xq6t9PUV08aBZ4Lutqq2LEHM486bpZqoViScog==",
"peer": true,
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/@opentelemetry/api-metrics": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/api-metrics/-/api-metrics-0.27.0.tgz",
"integrity": "sha512-tB79288bwjkdhPNpw4UdOEy3bacVwtol6Que7cAu8KEJ9ULjRfSiwpYEwJY/oER3xZ7zNFz0uiJ7N1jSiotpVA==",
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/@opentelemetry/core": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.0.1.tgz",
"integrity": "sha512-90nQ2X6b/8X+xjcLDBYKooAcOsIlwLRYm+1VsxcX5cHl6V4CSVmDpBreQSDH/A21SqROzapk6813008SatmPpQ==",
"dependencies": {
"@opentelemetry/semantic-conventions": "1.0.1"
},
"engines": {
"node": ">=8.5.0"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.0.0 <1.1.0"
}
},
"node_modules/@opentelemetry/exporter-metrics-otlp-http": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.27.0.tgz",
"integrity": "sha512-97eAPtA9po403CpNnd4n8HtEN6HbXwb05eUL5Jxaj70RSKAHBKjAFG4/Bk75DX3G+glHN5Gm/waMmcuBqFW5rA==",
"dependencies": {
"@opentelemetry/api-metrics": "0.27.0",
"@opentelemetry/core": "1.0.1",
"@opentelemetry/exporter-trace-otlp-http": "0.27.0",
"@opentelemetry/resources": "1.0.1",
"@opentelemetry/sdk-metrics-base": "0.27.0"
},
"engines": {
"node": ">=8.0.0"
},
"peerDependencies": {
"@opentelemetry/api": "^1.0.3"
}
},
"node_modules/@opentelemetry/exporter-trace-otlp-http": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.27.0.tgz",
"integrity": "sha512-ZE8Ns/GGW83E4igrby69shiqEkVo+cULzbm4DprSEMCWrPAL/NBobETFOiOQyBBBgIfrhi5EG6truUiafB1cMQ==",
"dependencies": {
"@opentelemetry/core": "1.0.1",
"@opentelemetry/resources": "1.0.1",
"@opentelemetry/sdk-trace-base": "1.0.1"
},
"engines": {
"node": ">=8.0.0"
},
"peerDependencies": {
"@opentelemetry/api": "^1.0.0"
}
},
"node_modules/@opentelemetry/resources": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.0.1.tgz",
"integrity": "sha512-p8DevOaAEepPucUtImR4cZKHOE2L1jgQAtkdZporV+XnxPA/HqCHPEESyUVuo4f5M0NUlL6k5Pba75KwNJlTRg==",
"dependencies": {
"@opentelemetry/core": "1.0.1",
"@opentelemetry/semantic-conventions": "1.0.1"
},
"engines": {
"node": ">=8.0.0"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.0.0 <1.1.0"
}
},
"node_modules/@opentelemetry/sdk-metrics-base": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics-base/-/sdk-metrics-base-0.27.0.tgz",
"integrity": "sha512-HpiWI4sVNsjp3FGyUlc24KvUY2Whl4PQVwcbA/gWv2kHaLQrDJrWC+3rjUR+87Mrd0nsiqJ85xhGFU6IK8h7gg==",
"dependencies": {
"@opentelemetry/api-metrics": "0.27.0",
"@opentelemetry/core": "1.0.1",
"@opentelemetry/resources": "1.0.1",
"lodash.merge": "^4.6.2"
},
"engines": {
"node": ">=8.0.0"
},
"peerDependencies": {
"@opentelemetry/api": "^1.0.0"
}
},
"node_modules/@opentelemetry/sdk-trace-base": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.0.1.tgz",
"integrity": "sha512-JVSAepTpW7dnqfV7XFN0zHj1jXGNd5OcvIGQl76buogqffdgJdgJWQNrOuUJaus56zrOtlzqFH+YtMA9RGEg8w==",
"dependencies": {
"@opentelemetry/core": "1.0.1",
"@opentelemetry/resources": "1.0.1",
"@opentelemetry/semantic-conventions": "1.0.1"
},
"engines": {
"node": ">=8.0.0"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.0.0 <1.1.0"
}
},
"node_modules/@opentelemetry/semantic-conventions": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.0.1.tgz",
"integrity": "sha512-7XU1sfQ8uCVcXLxtAHA8r3qaLJ2oq7sKtEwzZhzuEXqYmjW+n+J4yM3kNo0HQo3Xp1eUe47UM6Wy6yuAvIyllg==",
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/@peculiar/asn1-cms": {
"version": "2.0.44",
"license": "MIT",
@ -5386,7 +5510,6 @@
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"dev": true,
"license": "MIT"
},
"node_modules/lodash.mergewith": {
@ -10497,6 +10620,7 @@
"license": "Apache 2.0",
"dependencies": {
"@boxyhq/saml20": "0.2.0",
"@opentelemetry/api-metrics": "0.27.0",
"@peculiar/webcrypto": "1.2.3",
"@peculiar/x509": "1.6.1",
"cors": "2.8.5",
@ -11091,6 +11215,7 @@
"version": "file:npm",
"requires": {
"@boxyhq/saml20": "0.2.0",
"@opentelemetry/api-metrics": "0.27.0",
"@peculiar/webcrypto": "1.2.3",
"@peculiar/x509": "1.6.1",
"@types/express": "4.17.13",
@ -11423,6 +11548,82 @@
"fastq": "^1.6.0"
}
},
"@opentelemetry/api": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.0.4.tgz",
"integrity": "sha512-BuJuXRSJNQ3QoKA6GWWDyuLpOUck+9hAXNMCnrloc1aWVoy6Xq6t9PUV08aBZ4Lutqq2LEHM486bpZqoViScog==",
"peer": true
},
"@opentelemetry/api-metrics": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/api-metrics/-/api-metrics-0.27.0.tgz",
"integrity": "sha512-tB79288bwjkdhPNpw4UdOEy3bacVwtol6Que7cAu8KEJ9ULjRfSiwpYEwJY/oER3xZ7zNFz0uiJ7N1jSiotpVA=="
},
"@opentelemetry/core": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.0.1.tgz",
"integrity": "sha512-90nQ2X6b/8X+xjcLDBYKooAcOsIlwLRYm+1VsxcX5cHl6V4CSVmDpBreQSDH/A21SqROzapk6813008SatmPpQ==",
"requires": {
"@opentelemetry/semantic-conventions": "1.0.1"
}
},
"@opentelemetry/exporter-metrics-otlp-http": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.27.0.tgz",
"integrity": "sha512-97eAPtA9po403CpNnd4n8HtEN6HbXwb05eUL5Jxaj70RSKAHBKjAFG4/Bk75DX3G+glHN5Gm/waMmcuBqFW5rA==",
"requires": {
"@opentelemetry/api-metrics": "0.27.0",
"@opentelemetry/core": "1.0.1",
"@opentelemetry/exporter-trace-otlp-http": "0.27.0",
"@opentelemetry/resources": "1.0.1",
"@opentelemetry/sdk-metrics-base": "0.27.0"
}
},
"@opentelemetry/exporter-trace-otlp-http": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.27.0.tgz",
"integrity": "sha512-ZE8Ns/GGW83E4igrby69shiqEkVo+cULzbm4DprSEMCWrPAL/NBobETFOiOQyBBBgIfrhi5EG6truUiafB1cMQ==",
"requires": {
"@opentelemetry/core": "1.0.1",
"@opentelemetry/resources": "1.0.1",
"@opentelemetry/sdk-trace-base": "1.0.1"
}
},
"@opentelemetry/resources": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.0.1.tgz",
"integrity": "sha512-p8DevOaAEepPucUtImR4cZKHOE2L1jgQAtkdZporV+XnxPA/HqCHPEESyUVuo4f5M0NUlL6k5Pba75KwNJlTRg==",
"requires": {
"@opentelemetry/core": "1.0.1",
"@opentelemetry/semantic-conventions": "1.0.1"
}
},
"@opentelemetry/sdk-metrics-base": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics-base/-/sdk-metrics-base-0.27.0.tgz",
"integrity": "sha512-HpiWI4sVNsjp3FGyUlc24KvUY2Whl4PQVwcbA/gWv2kHaLQrDJrWC+3rjUR+87Mrd0nsiqJ85xhGFU6IK8h7gg==",
"requires": {
"@opentelemetry/api-metrics": "0.27.0",
"@opentelemetry/core": "1.0.1",
"@opentelemetry/resources": "1.0.1",
"lodash.merge": "^4.6.2"
}
},
"@opentelemetry/sdk-trace-base": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.0.1.tgz",
"integrity": "sha512-JVSAepTpW7dnqfV7XFN0zHj1jXGNd5OcvIGQl76buogqffdgJdgJWQNrOuUJaus56zrOtlzqFH+YtMA9RGEg8w==",
"requires": {
"@opentelemetry/core": "1.0.1",
"@opentelemetry/resources": "1.0.1",
"@opentelemetry/semantic-conventions": "1.0.1"
}
},
"@opentelemetry/semantic-conventions": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.0.1.tgz",
"integrity": "sha512-7XU1sfQ8uCVcXLxtAHA8r3qaLJ2oq7sKtEwzZhzuEXqYmjW+n+J4yM3kNo0HQo3Xp1eUe47UM6Wy6yuAvIyllg=="
},
"@peculiar/asn1-cms": {
"version": "2.0.44",
"requires": {
@ -14169,8 +14370,7 @@
"dev": true
},
"lodash.merge": {
"version": "4.6.2",
"dev": true
"version": "4.6.2"
},
"lodash.mergewith": {
"version": "4.6.2",

View File

@ -39,6 +39,9 @@
},
"dependencies": {
"@boxyhq/saml-jackson": "file:./npm",
"@opentelemetry/api-metrics": "0.27.0",
"@opentelemetry/exporter-metrics-otlp-http": "0.27.0",
"@opentelemetry/sdk-metrics-base": "0.27.0",
"cors": "2.8.5",
"next": "12.0.10",
"react": "17.0.2",