From c158e0700d96f3b08dda0a987a915a29b36af40d Mon Sep 17 00:00:00 2001
From: Dominik Sigmund <dominik.sigmund@br.de>
Date: Fri, 3 Apr 2020 15:27:24 +0200
Subject: [PATCH] Almost Done

---
 .gitlab-ci.yml      | 50 ++++++++++++++++++++++++++++++++++++++
 .npmignore          |  3 ++-
 README.md           | 32 +++++++++++++++++++-----
 TODO.md             |  6 ++---
 examples/src/app.ts |  7 +++++-
 package.json        |  4 +++
 src/index.spec.ts   |  6 +++++
 src/index.ts        | 59 ++++++++++++++++++++++++++++++++++++---------
 8 files changed, 145 insertions(+), 22 deletions(-)
 create mode 100644 .gitlab-ci.yml

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..cc391a8
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,50 @@
+include:
+  - project: 'general/templates'
+    file: '/cicd/SAST-nodejs.gitlab-ci.yml'
+  - project: 'general/templates'
+    file: '/cicd/npm-audit.gitlab-ci.yml'
+  - project: 'general/templates'
+    file: '/cicd/sonarqube.gitlab-ci.yml'
+  - project: 'general/templates'
+    file: '/cicd/npm-outdated.gitlab-ci.yml' 
+
+variables:
+  SONAR_PROJECT_KEY: metrics
+  SONAR_TOKEN: 11922a8e774494f51e1d2f0e695949e4073e7df8
+  NPM_REGISTRY: https://npm.br-edv.brnet.int
+  NPM_TOKEN: 5w2Gy80rdH+2Tch0afNI6Q==
+
+cache:
+  paths:
+    - node_modules/
+    - docs/
+
+stages:
+  - build
+  - test
+  - quality
+  - publish
+
+build:
+  stage: build
+  script:
+    - npm install
+    - npm run build
+
+test:
+  stage: test
+  before_script:
+    - npm install -g jest
+  script:
+    - jest
+  artifacts:
+    paths:
+      - docs/test-report.html
+      - docs/coverage/lcov.info
+
+publish:
+  stage: publish
+  script:
+    - npm config set strict-ssl false
+    - npm config set //${NPM_REGISTRY}/:_authToken ${NPM_TOKEN}
+    - npm publish --registry $NPM_REGISTRY
diff --git a/.npmignore b/.npmignore
index 240193a..e0b3277 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,2 +1,3 @@
 src/
-docs/
\ No newline at end of file
+docs/
+examples/
\ No newline at end of file
diff --git a/README.md b/README.md
index edd7797..ae22441 100644
--- a/README.md
+++ b/README.md
@@ -17,14 +17,34 @@ A small express middleware to get base metrics for any node.js app.
 `import { Metrics } from '@br/metrics'`  
 `let metrics = new Metrics(options)`
 
-Note: The options Part may be omitted, as all parts are optional.
+Note: The options Part may be omitted, as all parts are optional.  
 
-Before your Routes:
-`router.use(metrics.start.bind(metrics))`
+Before your Routes:  
+`router.use(metrics.start.bind(metrics))`  
 
-And to enable the *_metrics*-Endpoint:
-`router.get('/_metrics', metrics.endpoint)`
+And to enable the *_metrics*-Endpoint:  
+`router.get('/_metrics', metrics.endpoint)`  
 
 ### Options
 
-TODO: fill options
\ No newline at end of file
+The Following Options may be used to configure the behaviour.
+
+- ignore: A String Array with routes to ignore, e.g. ['/foo'] . Default: []. Important: */_metrics* and */favicon.ico* are always ignored
+- disableErrorCounter: Disable the Error Counter. Default: false
+- disableRouteCounter: Disable the Route Counter. Default: false
+- disableDurationCounter: Disable the Duration Counter. Default: false
+
+## Examples
+
+You can find prebuilt examples in the fitting folder.
+
+Just call `node examples/dist/server.js 3000` to start a Test-Server on Port 3000.
+
+Then use your Browser to call the Endpoints:  
+
+- /foo
+- /bar
+- /404
+- /401
+
+And check the results on the Endpoint */_metrics*
diff --git a/TODO.md b/TODO.md
index dac536c..8f74238 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,7 +1,7 @@
 # TODO
 
-- config
-
 - tests
 
-- README: options, examples
\ No newline at end of file
+- get to gitlab-server
+
+- publish to npm
diff --git a/examples/src/app.ts b/examples/src/app.ts
index ba2f4cb..021f7b2 100644
--- a/examples/src/app.ts
+++ b/examples/src/app.ts
@@ -17,7 +17,12 @@ class App {
 
     this.router = express.Router()
 
-    this.metrics = new Metrics({})
+    this.metrics = new Metrics({
+      ignore: ['/bar'],
+      disableErrorCounter: false,
+      disableRouteCounter: false,
+      disableDurationCounter: false
+    })
 
     this.router.use(this.metrics.start.bind(this.metrics))
 
diff --git a/package.json b/package.json
index 693a382..a0d8497 100644
--- a/package.json
+++ b/package.json
@@ -5,6 +5,7 @@
   "main": "dist/index.js",
   "types": "dist/index.d.ts",
   "scripts": {
+    "prepublish":"npm run build",
     "test": "jest",
     "test:mutation": "stryker run",
     "lint": "eslint src/**/*.ts",
@@ -55,5 +56,8 @@
       "pre-push": "npm run lint",
       "post-commit": "./ho-copy"
     }
+  },
+  "publishConfig": {
+    "@br:registry": "https://npm.br-edv.brnet.int"
   }
 }
diff --git a/src/index.spec.ts b/src/index.spec.ts
index e69de29..64c185f 100644
--- a/src/index.spec.ts
+++ b/src/index.spec.ts
@@ -0,0 +1,6 @@
+/*
+  Import.
+  - Start with different option packages.
+  - Call all Routes
+  - Check if _metrics has a good start
+*/
diff --git a/src/index.ts b/src/index.ts
index 969af81..34f8900 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,14 +1,47 @@
 import * as express from 'express'
 import Prometheus = require('prom-client')
 
+export interface Options {
+  ignore: string[]
+  disableRouteCounter: boolean
+  disableErrorCounter: boolean
+  disableDurationCounter: boolean
+}
+
 export class Metrics {
-  private readonly _options: any
+  private readonly _ignore: string[]
+  private readonly _disableRouteCounter: boolean
+  private readonly _disableErrorCounter: boolean
+  private readonly _disableDurationCounter: boolean
+
   public readonly _httpRequestDurationMicroseconds: any
   public readonly _numOfRequests: any
   public readonly _numOfErrors: any
 
-  constructor (options: any) {
-    this._options = options
+  constructor (options: Partial<Options> = {}) {
+    if (typeof options.ignore !== 'undefined') {
+      this._ignore = options.ignore
+      this._ignore.push('/_metrics')
+      this._ignore.push('/favicon.ico')
+    } else {
+      this._ignore = ['/_metrics', '/favicon.ico']
+    }
+    if (typeof options.disableRouteCounter !== 'undefined') {
+      this._disableRouteCounter = options.disableRouteCounter
+    } else {
+      this._disableRouteCounter = false
+    }
+    if (typeof options.disableErrorCounter !== 'undefined') {
+      this._disableErrorCounter = options.disableErrorCounter
+    } else {
+      this._disableErrorCounter = false
+    }
+    if (typeof options.disableDurationCounter !== 'undefined') {
+      this._disableDurationCounter = options.disableDurationCounter
+    } else {
+      this._disableDurationCounter = false
+    }
+
     this._httpRequestDurationMicroseconds = new Prometheus.Histogram({
       name: 'http_request_duration_ms',
       help: 'Duration of HTTP requests in ms',
@@ -25,20 +58,25 @@ export class Metrics {
       help: 'Number of errors',
       labelNames: ['error']
     })
-    // TODO: config: ignore routes, disable metrics
   }
 
   public start (req: express.Request, res: express.Response, next: express.NextFunction): void {
     res.locals.startEpoch = Date.now()
     res.on('finish', () => {
-      if (req.originalUrl !== '/_metrics' && req.originalUrl !== './favicon.ico') {
+      if (!this._ignore.includes(req.originalUrl)) {
         const responseTimeInMs = Date.now() - res.locals.startEpoch
-        this._httpRequestDurationMicroseconds
-          .labels(req.method, req.originalUrl, res.statusCode.toString())
-          .observe(responseTimeInMs)
-        this._numOfRequests.inc({ route: req.originalUrl })
+        if (!this._disableDurationCounter) {
+          this._httpRequestDurationMicroseconds
+            .labels(req.method, req.originalUrl, res.statusCode.toString())
+            .observe(responseTimeInMs)
+        }
+        if (!this._disableRouteCounter) {
+          this._numOfRequests.inc({ route: req.originalUrl })
+        }
         if (res.statusCode >= 400) {
-          this._numOfErrors.inc({ error: res.statusCode })
+          if (!this._disableErrorCounter) {
+            this._numOfErrors.inc({ error: res.statusCode })
+          }
         }
       }
     })
@@ -50,5 +88,4 @@ export class Metrics {
     res.end(Prometheus.register.metrics())
   }
 }
-
 export default Metrics
-- 
GitLab