Skip to content

Commit

Permalink
feat(metrics): Initial implementation of package install/download met…
Browse files Browse the repository at this point in the history
…rics capturing and metrics endpoint
  • Loading branch information
Ed Clement committed Dec 23, 2021
1 parent 98c1b4d commit 11e8ac6
Show file tree
Hide file tree
Showing 22 changed files with 28,389 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"presets": [
["@verdaccio", { "typescript": true }]
]
}
22 changes: 22 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
version: 2.1

orbs:
node: circleci/node@4.7.0

jobs:
test:
docker:
- image: 'node:lts-alpine'
steps:
- checkout
- node/install-packages
- run:
command: npm run test
# https://circleci.com/docs/2.0/collect-test-data
- store_test_results:
path: ./coverage/

workflows:
test:
jobs:
- test
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# top-most EditorConfig file
root = true

[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
indent_style = space

[*.{ts,js,mjs,json,txt,yml,yaml}]
indent_size = 2
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
coverage/
lib/
node_modules/
8 changes: 8 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": ["@verdaccio"],
"rules": {
"no-case-declarations": "off",
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/ban-ts-comment": 0
}
}
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
_storage/
lib/
node_modules/
coverage/
.idea/

npm-debug.log*
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npm test
13 changes: 13 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
src/
test/

.babelrc
.editorconfig
.eslintignore
.eslintrc
.gitignore
.npmignore
metrics.ts
jest.config.js
README.md
tsconfig.json
79 changes: 78 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,79 @@
# verdaccio-metrics-middleware
Verdaccio middleware plugin used to collect prometheus compatible metrics
Metrics middleware plugin for Verdaccio. Collects metrics specifically for package install/download requests and
exposes them at a configurable metrics endpoint (defaults to `/-/metrics`). The metrics are produced in the standard
[prometheus metrics text format](https://prometheus.io/docs/instrumenting/exposition_formats/#text-format-example).

A [counter](https://prometheus.io/docs/concepts/metric_types/#counter) metric is used to track the number of package
installs/downloads. The following [labels](https://prometheus.io/docs/practices/naming/#labels) are applied to _every_
request:
- `username` - The Verdaccio username of the user attempting to install/download a package. If the request is
unauthenticated then the value `UNKNOWN` is used.
- `userAgentName` - The name of the user agent the client used to make the request. It is derived from the `user-agent`
header on the request. If no `user-agent` header is provided it defaults to `UNKNOWN`.
- `statusCode` - The status code of the response from Verdaccio.

Optionally, an additional `packageGroup` label can be applied *if* a `packageGroups` option is added to the plugin
configuration.

## Configuration
Complete configuration example:
```yaml
middlewares:
metrics:
## Optional. Defaults to `false` so make sure to set this to `true` if you want to collect metrics.
enabled: true

## Optional. Defaults to `/-/metrics`.
metricsPath: /custom/path/metrics

## Optional. A map of regular expressions to package grouping names.
packageGroups:
## NOTE: The order of items below matters. The first matched regex is the package grouping that will be applied
## to the metric generated for a request.
'@angular[/][^/]*': angular
'react': react
'.*': other
```
## Package Groups
The `packageGroups` configuration option accepts an object map whose keys are expected to be a regular expression string
and the value the name of the package group that should be used for the `packageGroup` metric label. If no
`packageGroups` are defined, a `packageGroup` [label](https://prometheus.io/docs/practices/naming/#labels) will NOT be
applied to the [counter](https://prometheus.io/docs/concepts/metric_types/#counter) metric.

The regular expression key is evaluated against the request path in the following manner:
```javascript
// scoped packages generally have the `/` url encoded to `%2f`
new RegExp(packageGroupRegex).test(decodeURIComponent(request.path))
```

The order of the keys/values in the object map matters. The regular expressions are evaluated from first to last in the
order they are listed under the `packageGroups` configuration option and the first matching regex will have the
corresponding package grouping value applied when the install/download counter metric is collected.

Given the following example configuration:
```yaml
# Verdaccio config file
middlewares:
metrics:
enabled: true
packageGroups:
'@babel[/]plugin': 'babel-plugin'
'babel[-]plugin': 'babel-plugin'
'babel': 'babel'
'@.*': scoped
'.*': other
```
... the following packages would resolve to the `packageGroup` as listed in the table:

| Package Name | Package Group |
|-----------------------------------|---------------|
| `@babel/core` | babel |
| `@babel/parser` | babel |
| `@babel/plugin-transform-runtime` | babel-plugin |
| `babel-plugin-istanbul` | babel-plugin |
| `babel-jest` | babel |
| `@angular/core` | scoped |
| `@apollo/client` | scoped |
| `react` | other |
| `apollo-server-express` | other |
11 changes: 11 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = {
name: 'verdaccio-metrics-middleware',
verbose: true,
collectCoverage: true,
collectCoverageFrom: ['src/**/*.ts', '!src/index.ts'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
transform: {
'^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
},
reporters: ['default', ['jest-junit', { outputDirectory: './coverage/jest', outputName: 'results.xml' }]],
};
Loading

0 comments on commit 11e8ac6

Please sign in to comment.