From c78315a0b93b65ce52cdcc8f2d856ead6a758c1a Mon Sep 17 00:00:00 2001 From: Zong Jhe Wu Date: Fri, 12 Jun 2020 22:50:50 +0800 Subject: [PATCH 1/2] Add getViewMetrics method --- package-lock.json | 14 +++++----- package.json | 2 ++ rollup.config.js | 3 ++- src/glasnostic-api.ts | 62 +++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 72 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6d43aee..92682a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -100,6 +100,12 @@ "integrity": "sha512-vEcX7S7aPhsBCivxMwAANQburHBtfN9RdyXFk84IJmu2Z4Hkg1tOFgaslRiEqqvoLtbCBi6ika1EMspE+NZ9Lg==", "dev": true }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, "@types/node": { "version": "14.0.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.10.tgz", @@ -140,14 +146,12 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -221,8 +225,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "decompress-response": { "version": "6.0.0", @@ -414,7 +417,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } diff --git a/package.json b/package.json index eba929a..32e761b 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "devDependencies": { "@rollup/plugin-typescript": "^4.1.2", "@types/lodash": "^4.14.155", + "@types/minimatch": "^3.0.3", "@types/tough-cookie": "^4.0.0", "prettier": "^2.0.5", "rollup": "^2.15.0", @@ -30,6 +31,7 @@ "dependencies": { "got": "^11.2.0", "lodash": "^4.17.15", + "minimatch": "^3.0.4", "tough-cookie": "^4.0.0" } } diff --git a/rollup.config.js b/rollup.config.js index 0407e19..2b1237b 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -10,7 +10,8 @@ export default { external: [ 'got', 'tough-cookie', - 'lodash' + 'lodash', + 'minimatch' ], plugins: [typescript({ declaration: true, diff --git a/src/glasnostic-api.ts b/src/glasnostic-api.ts index 6902519..7199670 100644 --- a/src/glasnostic-api.ts +++ b/src/glasnostic-api.ts @@ -1,12 +1,12 @@ import { CookieJar } from 'tough-cookie'; import { default as got } from 'got'; import { isNil } from 'lodash'; +import { makeRe } from 'minimatch'; import { PolicyHistory } from './policy-history'; import { Policies } from './policies'; import { View } from './view'; import { Environment } from './environment'; -import { MetricsResponse } from './metrics'; -import {RouteMetric} from "./metrics"; +import { RouteMetric, MetricsResponse, MetricsNodeMap, MetricsRouteHistory, MetricsRouteSpec } from './metrics'; export * from './policies'; export * from './metric-types'; @@ -268,4 +268,62 @@ export class GlasnosticConsole { return got.post(url, options).json(); } + + private filterMetricsByView( + nodes: MetricsNodeMap, + routes: MetricsRouteHistory[], + source: string, + destination: string + ): MetricsRouteHistory[] { + interface Name { + src: string; + dst: string; + } + const parsePatterns = (patterns: string): RegExp[] => { + return patterns + .split(',') + .map((s) => makeRe(s.trim())) + .filter((p) => !!p); + }; + const match = (patterns: RegExp[], subject: string): boolean => { + return patterns.some((p) => p.test(subject)); + }; + const lookupName = (spec: MetricsRouteSpec, nodes: MetricsNodeMap): Name => { + const routeNodes = spec.map((s) => nodes[s]); + const [src, dst] = routeNodes.map((n) => + [n?.name, n?.instance].filter((s) => !!s).join(' ') + ); + return { src, dst }; + }; + + const srcPatterns = parsePatterns(source); + const dstPatterns = parsePatterns(destination); + return routes.filter((route) => { + const { src, dst } = lookupName(route.spec, nodes); + return match(srcPatterns, src) && match(dstPatterns, dst); + }); + } + + async getViewMetrics( + environmentKey: string, + viewIndex: string, + samplePeriod?: number, + duration?: number, + start?: number + ): Promise { + const getMetrics = this.getMetrics(environmentKey, samplePeriod, duration, start); + const getView = this.getView(environmentKey, viewIndex); + const [res, view] = await Promise.all([getMetrics, getView]); + if (!view) { + throw new Error('view not found'); + } + if (!res.nodes || !res.routes) { + return res; + } + const routes = this.filterMetricsByView(res.nodes, res.routes, view.clients, view.services); + return { + ...res, + routes, + }; + } } From c1a18f374b978a9ae86e89b38e6b4aed13d8706d Mon Sep 17 00:00:00 2001 From: Marcus Schiesser Date: Mon, 15 Jun 2020 19:24:01 +0800 Subject: [PATCH 2/2] added example for capturing view traffic --- example/get-metrics.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/example/get-metrics.js b/example/get-metrics.js index 36278e5..1ba3fd5 100644 --- a/example/get-metrics.js +++ b/example/get-metrics.js @@ -10,6 +10,9 @@ const { GlasnosticConsole } = require('../dist/glasnostic-api'); console.log(`logged in as ${username}`); const environments = await api.getEnvironments(); + // create a view that is capturing the traffic + const view = await api.createView(environments[0].key, 'My Channel', 'source', 'destination'); + console.log('created view:', view); // send metric data to the first network in the first environment const networkKey = environments[0].clusters[0].key; const metric = [{ @@ -27,12 +30,12 @@ const { GlasnosticConsole } = require('../dist/glasnostic-api'); await api.sendMetric(networkKey, new Date(), metric); console.log('metric sent.'); // gets data from the last minute (=60000 milliseconds) in 10s samples (=10000 milliseconds) - const metrics = await api.getMetrics(environments[0].key, 10000, 60000); + const metrics = await api.getViewMetrics(environments[0].key, view.index,10000, 60000); console.log('initial metrics:', metrics); // send 2nd metric await api.sendMetric(environments[0].clusters[0].key, new Date(), metric); console.log('2nd metric sent.'); - // get 20s of metrics after the last time getMetrics was called - const incrementalMetrics = await api.getMetrics(environments[0].key, 10000, 20000, metrics.window.start); + // get 30s of metrics after the last time getViewMetrics was called + const incrementalMetrics = await api.getViewMetrics(environments[0].key, view.index,10000, 30000, metrics.window.start); console.log('metrics update:', incrementalMetrics); })(); \ No newline at end of file