Full Code of felixge/node-measured for AI

master 916cb3ae8aa7 cached
90 files
248.9 KB
65.5k tokens
229 symbols
1 requests
Download .txt
Showing preview only (275K chars total). Download the full file or copy to clipboard to get everything.
Repository: felixge/node-measured
Branch: master
Commit: 916cb3ae8aa7
Files: 90
Total size: 248.9 KB

Directory structure:
gitextract_rxmrbihn/

├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── .jsdoc.json
├── .prettierrc
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── Readme.md
├── documentation/
│   ├── assets/
│   │   └── measured.license.md
│   └── docstrap_customized/
│       └── template/
│           └── publish.js
├── lerna.json
├── package.json
├── packages/
│   ├── measured-core/
│   │   ├── README.md
│   │   ├── lib/
│   │   │   ├── Collection.js
│   │   │   ├── index.js
│   │   │   ├── metrics/
│   │   │   │   ├── CachedGauge.js
│   │   │   │   ├── Counter.js
│   │   │   │   ├── Gauge.js
│   │   │   │   ├── Histogram.js
│   │   │   │   ├── Meter.js
│   │   │   │   ├── Metric.js
│   │   │   │   ├── NoOpMeter.js
│   │   │   │   ├── SettableGauge.js
│   │   │   │   └── Timer.js
│   │   │   ├── util/
│   │   │   │   ├── BinaryHeap.js
│   │   │   │   ├── ExponentiallyDecayingSample.js
│   │   │   │   ├── ExponentiallyMovingWeightedAverage.js
│   │   │   │   ├── Stopwatch.js
│   │   │   │   └── units.js
│   │   │   └── validators/
│   │   │       └── metricValidators.js
│   │   ├── package.json
│   │   └── test/
│   │       ├── common.js
│   │       ├── integration/
│   │       │   └── test-Collection_end.js
│   │       └── unit/
│   │           ├── metrics/
│   │           │   ├── test-CachedGauge.js
│   │           │   ├── test-Counter.js
│   │           │   ├── test-Gauge.js
│   │           │   ├── test-Histogram.js
│   │           │   ├── test-Meter.js
│   │           │   ├── test-NoOpMeter.js
│   │           │   ├── test-SettableGauge.js
│   │           │   └── test-Timer.js
│   │           ├── test-Collection.js
│   │           └── util/
│   │               ├── test-BinaryHeap.js
│   │               ├── test-ExponentiallyDecayingSample.js
│   │               ├── test-ExponentiallyMovingWeightedAverage.js
│   │               └── test-Stopwatch.js
│   ├── measured-node-metrics/
│   │   ├── README.md
│   │   ├── lib/
│   │   │   ├── index.js
│   │   │   ├── nodeHttpRequestMetrics.js
│   │   │   ├── nodeOsMetrics.js
│   │   │   ├── nodeProcessMetrics.js
│   │   │   └── utils/
│   │   │       └── CpuUtils.js
│   │   ├── package.json
│   │   └── test/
│   │       ├── integration/
│   │       │   ├── test-express-middleware.js
│   │       │   └── test-koa-middleware.js
│   │       └── unit/
│   │           ├── TestReporter.js
│   │           ├── test-nodeHttpRequestMetrics.js
│   │           ├── test-nodeOsMetrics.js
│   │           ├── test-nodeProcessMetrics.js
│   │           └── utils/
│   │               └── test-CpuUtils.js
│   ├── measured-reporting/
│   │   ├── README.md
│   │   ├── lib/
│   │   │   ├── @types/
│   │   │   │   └── types.js
│   │   │   ├── index.js
│   │   │   ├── registries/
│   │   │   │   ├── DimensionAwareMetricsRegistry.js
│   │   │   │   └── SelfReportingMetricsRegistry.js
│   │   │   ├── reporters/
│   │   │   │   ├── LoggingReporter.js
│   │   │   │   └── Reporter.js
│   │   │   └── validators/
│   │   │       └── inputValidators.js
│   │   ├── package.json
│   │   └── test/
│   │       └── unit/
│   │           ├── registries/
│   │           │   ├── test-DimensionAwareMetricsRegistry.js
│   │           │   └── test-SelfReportingMetricsRegistry.js
│   │           ├── reporters/
│   │           │   ├── test-LoggingReporter.js
│   │           │   └── test-Reporter.js
│   │           └── validators/
│   │               └── test-inputValidators.js
│   └── measured-signalfx-reporter/
│       ├── README.md
│       ├── lib/
│       │   ├── SignalFxEventCategories.js
│       │   ├── index.js
│       │   ├── registries/
│       │   │   └── SignalFxSelfReportingMetricsRegistry.js
│       │   ├── reporters/
│       │   │   └── SignalFxMetricsReporter.js
│       │   └── validators/
│       │       └── inputValidators.js
│       ├── package.json
│       └── test/
│           ├── unit/
│           │   ├── registries/
│           │   │   └── test-SignalFxSelfReportingMetricsRegistry.js
│           │   ├── reporters/
│           │   │   └── test-SignalFxMetricsReporter.js
│           │   └── validators/
│           │       └── test-inputValidators.js
│           └── user-acceptance-test/
│               └── index.js
├── scripts/
│   ├── generate-docs.sh
│   └── publish.sh
└── tutorials/
    ├── SignalFx Express Full End to End Example.md
    └── SignalFx Koa Full End to End Example.md

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintignore
================================================
node_modules/

================================================
FILE: .eslintrc.json
================================================
{
  "extends": "airbnb/base",
  "env": {
    "jest": true
  },
  "rules": {
    "max-len": 0,
    "no-underscore-dangle": 0,
    "no-use-before-define": 0,
    "object-shorthand": 0,
    "comma-dangle": 0,
    "class-methods-use-this": 0,
    "no-param-reassign": 0,
    "no-constant-condition": 0,
    "no-plusplus": 0,
    "one-var-declaration-per-line": 0,
    "one-var": 0,
    "prefer-destructuring": ["error", {
      "array": false,
      "object": true
    }],
    "arrow-body-style": 0,
    "no-mixed-operators": 0,
    "arrow-parens": 0,
    "function-paren-newline": 0,
    "no-unused-vars": 0,
    "object-curly-newline": 0,
    "spaced-comment": 0
  }
}

================================================
FILE: .gitignore
================================================
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# next.js build output
.next

# Idea
.idea

**build/

*.un~

**/.DS_Store

================================================
FILE: .jsdoc.json
================================================
{
  "tags": {
    "allowUnknownTags": true
  },
  "plugins": ["plugins/markdown"],
  "templates": {
    "logoFile": "img/measured.png",
    "cleverLinks": false,
    "monospaceLinks": false,
    "dateFormat": "ddd MMM Do YYYY",
    "outputSourceFiles": true,
    "outputSourcePath": true,
    "systemName": "Measured",
    "copyright": "License: MIT. Measured Copyright © 2012-2017 Felix Geisendörfer and Contributors, © 2018 Yet Another Org and Contributors. </br>Icon by <a href=\"http://www.simpleicon.com/\">SimpleIcon</a> <a href=\"https://creativecommons.org/licenses/by/3.0\">[CC BY 3.0]</a>, <a href=\"https://commons.wikimedia.org/wiki/File:Simpleicons_Business_line-graphic-with-two-lines.svg\">via Wikimedia Commons</a>",
    "navType": "vertical",
    "theme": "cosmo",
    "linenums": true,
    "collapseSymbols": false,
    "inverseNav": true,
    "protocol": "html://",
    "methodHeadingReturns": false,
    "index": {
      "root": "./",
      "measured-core": "../../",
      "measured-reporting": "../../",
      "measured-signalfx-reporter": "../../"
    },
    "analytics":{"ua":"UA-119781742-1", "domain":"yaorg.github.io"}
  },
  "markdown": {
    "parser": "gfm",
    "hardwrap": true
  }
}


================================================
FILE: .prettierrc
================================================
printWidth: 120
tabWidth: 2
semi: true
singleQuote: true
bracketSpacing: true

================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
- 11
- 10
- 8
before_install:
- sudo apt-get -qq update
- sudo apt-get install -y gawk jq
jobs:
  include:
    - stage: publish code coverage
      node_js: "8"
      script:
      - npm run test:node:coverage
      - yarn coverage
    - stage: release docs
      if: type != pull_request AND branch = master
      node_js: "8"
      script:
      - yarn generate-docs
      - yarn travis-deploy-github-pages
    - stage: lerna publish and npm release
      if: type != pull_request AND tag IS present
      node_js: "8"
      script:
        - scripts/publish.sh
sudo: required
dist: xenial
addons:
  chrome: stable
env:
  global:
  - secure: ZKLEofNJCHSzJzfmayPgRdDWqD5N5g7OPs+gJELmwopAKCUaoOH4H5iH0eg1TZzcAoPL/qwU+gheEW1V7Io4PmVB2WUXUdBP9vaqZlrIw/sa6RD/51jpx4MkXd6ciXl1vmiWMnqPBj+S0NuYjKOt1tGMPDiOtK96UUVNA8uRMrs=
  - secure: sAfy698oA7zJdVEYt+MrBFlmbXIC0Xg+PSIA6bc6klp11yfgXS3vIXM5cW4MuijLJhxvPDmGzhsgVHB+pIQXffeVYKQypCp6JcoDG6OyUxUglvHoLaIfpMD+jQzu2I05EFCxyRZWrq+i5tMWZjkUPUfRJrXtnXEYqm2A5cWPOHs=


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

Pull requests are welcome, please keep conversations and commit messages civil.

1. Fork, then clone the repo.

1. Set up your machine.

    ```bash
    yarn && yarn bootstrap
    ```

1. Make sure the tests pass.
    
    ```bash
    yarn test
    ```

1. Make your change. Add tests for your change. Make the linter and tests pass.

    1. Document changes using the [jsdoc standards](http://usejsdoc.org/) to ensure that our code self-generates good documentation.
    
        build the jsdoc site, the files will be outputted to `./build/docs/`
        
        ```bash
        yarn generate-docs
        ```
        
        Validate that your generated documentation is what you intended, as documentation gets autogenerated from master.
    
    1. Run prettier to format code to comply with code style (Modified AirBnB Rule set: [ES Lint Config](.eslintrc.json))

        ```bash
        yarn format
        ```

    1. Make sure sure the linter and unit tests pass and the docs can be generated.

        ```bash
        yarn test
        ```

1. Push to your fork and submit a pull request and wait for peer review.

    We may suggest some changes or improvements or alternatives.
    
    Some things that will increase the chance that your pull request is accepted:
    
    1. Your code must be documented inline via jsdoc annotations, tested, and pass the linter.
    1. Your changes must not break the existing library API without good justification.
    1. Your commit messages should be reasonable. (`git rebase -i head~n` choose the r option to reword you commits).
    
This guide is loosely based off of [factory_bot_rails contributing.md](https://github.com/thoughtbot/factory_bot_rails/blob/master/CONTRIBUTING.md) which is referenced here [GitHub's Contributing Guidelines blog post](https://blog.github.com/2012-09-17-contributing-guidelines/)

## Releasing a new version

Once a pull request has been reviewed and merged new versions of all packages can be released by any of the maintainers. This is an automated process driven by [Github Release](https://github.com/yaorg/node-measured/releases).

1. Check the [latest version number under releases](https://github.com/yaorg/node-measured/releases) and decide if the changes to be released require a MAJOR, MINOR or PATCH release according to [semantic versioning](https://semver.org/):

    1. MAJOR version when you make incompatible API changes (e.g. `1.15.0` -> `2.0.0`)
    2. MINOR version when you add functionality in a backwards-compatible manner (e.g. `1.15.0` -> `1.16.0`)
    3. PATCH version when you make backwards-compatible bug fixes (e.g. `1.15.0` -> `1.15.1`

2. Create a new release by incrementing the correct version number using the [Github Releases user interface](https://github.com/yaorg/node-measured/releases/new).

    1. Be sure not to save any draft releases! (as they'll also trigger step 3 below since Github creates a new tag for draft releases).
    2. The tag version and release title is expected to be the same and in the following format: `v1.43.0`

3. The new tag will kick off a Travis build and using will automatically release all packages using the new version specified. (See [scripts/publish.sh](scripts/publish.sh) for details).

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2018 Yet Another Org and Contributors
Copyright (c) 2012-2017 Felix Geisendörfer and Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Readme.md
================================================
# Measured

Node libraries for measuring and reporting application-level metrics.

Measured is heavily inspired by Coda Hale, Yammer Inc's [Dropwizard Metrics Libraries](https://github.com/dropwizard/metrics)

[![Build Status](https://secure.travis-ci.org/yaorg/node-measured.png?branch=master)](http://travis-ci.org/yaorg/node-measured) [![Coverage Status](https://coveralls.io/repos/github/yaorg/node-measured/badge.svg?branch=master)](https://coveralls.io/github/yaorg/node-measured?branch=master)

## Available packages

### [Measured Core](packages/measured-core)

**The core measured library that has the Metric interfaces and implementations.**

[![npm](https://img.shields.io/npm/v/measured-core.svg)](https://www.npmjs.com/package/measured-core) [![downloads](https://img.shields.io/npm/dm/measured-core.svg)](https://www.npmjs.com/package/measured-core)

### [Measured Reporting](packages/measured-reporting)

**The registry and reporting library that has the classes needed to create a dimension aware, self reporting metrics registry.**

[![npm](https://img.shields.io/npm/v/measured-reporting.svg)](https://www.npmjs.com/package/measured-reporting) [![downloads](https://img.shields.io/npm/dm/measured-reporting.svg)](https://www.npmjs.com/package/measured-reporting)

### [Measured Node Metrics](packages/measured-node-metrics)

**Various metrics generators and http framework middlewares that can be used with a self reporting metrics registry to easily instrument metrics for a node app.**

[![npm](https://img.shields.io/npm/v/measured-node-metrics.svg)](https://www.npmjs.com/package/measured-node-metrics) [![downloads](https://img.shields.io/npm/dm/measured-node-metrics.svg)](https://www.npmjs.com/package/measured-node-metrics)

### [Measured SignalFx Reporter](packages/measured-signalfx-reporter)

**A reporter that can be used with measured-reporting to send metrics to [SignalFx](https://signalfx.com/).**

[![npm](https://img.shields.io/npm/v/measured-signalfx-reporter.svg)](https://www.npmjs.com/package/measured-signalfx-reporter) [![downloads](https://img.shields.io/npm/dm/measured-signalfx-reporter.svg)](https://www.npmjs.com/package/measured-signalfx-reporter)

### Measured Datadog reporter

**Not implemented, community contribution wanted.**

### Measured Graphite reporter

**Not implemented, community contribution wanted.**


## Development and Contributing

See [Development and Contributing](https://github.com/yaorg/node-measured/blob/master/CONTRIBUTING.md)

## License

This project Measured and all of its modules are licensed under the [MIT license](https://github.com/yaorg/node-measured/blob/master/LICENSE).


================================================
FILE: documentation/assets/measured.license.md
================================================
measured.png and measured.svg by [SimpleIcon](http://www.simpleicon.com/) available at [flaticon](http://www.flaticon.com/packs/simpleicon-business) 
Licenced by [CC BY 3.0](https://creativecommons.org/licenses/by/3.0), via Wikimedia Commons

================================================
FILE: documentation/docstrap_customized/template/publish.js
================================================
"use strict";

/**
 * @module template/publish
 * @type {*}
 */
/*global env: true */

var template = require('jsdoc/template'),
  doop = require('jsdoc/util/doop'),
  fs = require('jsdoc/fs'),
  _ = require('underscore'),
  path = require('jsdoc/path'),

  taffy = require('taffydb').taffy,
  handle = require('jsdoc/util/error').handle,
  helper = require('jsdoc/util/templateHelper'),
  moment = require("moment"),
  htmlsafe = helper.htmlsafe,
  sanitizeHtml = require('sanitize-html'),
  linkto = helper.linkto,
  resolveAuthorLinks = helper.resolveAuthorLinks,
  scopeToPunc = helper.scopeToPunc,
  hasOwnProp = Object.prototype.hasOwnProperty,
  conf = env.conf.templates || {},
  data,
  view,
  outdir = env.opts.destination,
  searchEnabled = conf.search !== false;

var globalUrl = helper.getUniqueFilename('global');
var indexUrl = helper.getUniqueFilename('index');

var packageName = process.env.PACKAGE_NAME;
var rootPath = !conf.index ? indexUrl : conf.index[packageName];

var navOptions = {
  includeDate: conf.includeDate !== false,
  logoFile: conf.logoFile  ? rootPath + conf.logoFile : "",
  systemName: conf.systemName || "Documentation",
  navType: conf.navType || "vertical",
  footer: conf.footer || "",
  copyright: conf.copyright || "",
  theme: conf.theme || "simplex",
  syntaxTheme: conf.syntaxTheme || "default",
  linenums: conf.linenums,
  collapseSymbols: conf.collapseSymbols || false,
  inverseNav: conf.inverseNav,
  outputSourceFiles: conf.outputSourceFiles === true,
  sourceRootPath: conf.sourceRootPath,
  disablePackagePath: conf.disablePackagePath,
  outputSourcePath: conf.outputSourcePath,
  dateFormat: conf.dateFormat,
  analytics: conf.analytics || null,
  methodHeadingReturns: conf.methodHeadingReturns === true,
  sort: conf.sort,
  search: searchEnabled,
  index: rootPath
};
var searchableDocuments = {};

var navigationMaster = {
  index: {
    title: navOptions.systemName,
    link: navOptions.index,
    members: []
  },
  namespace: {
    title: "Namespaces",
    link: helper.getUniqueFilename("namespaces.list"),
    members: []
  },
  module: {
    title: "Modules",
    link: helper.getUniqueFilename("modules.list"),
    members: []
  },
  class: {
    title: "Classes",
    link: helper.getUniqueFilename('classes.list'),
    members: []
  },

  mixin: {
    title: "Mixins",
    link: helper.getUniqueFilename("mixins.list"),
    members: []
  },
  event: {
    title: "Events",
    link: helper.getUniqueFilename("events.list"),
    members: []
  },
  interface: {
    title: "Interfaces",
    link: helper.getUniqueFilename("interfaces.list"),
    members: []
  },
  tutorial: {
    title: "Tutorials",
    link: helper.getUniqueFilename("tutorials.list"),
    members: []
  },
  global: {
    title: "Global",
    link: globalUrl,
    members: []

  },
  external: {
    title: "Externals",
    link: helper.getUniqueFilename("externals.list"),
    members: []
  }
};

function find(spec) {
  return helper.find(data, spec);
}

function tutoriallink(tutorial) {
  return helper.toTutorial(tutorial, null, {
    tag: 'em',
    classname: 'disabled',
    prefix: 'Tutorial: '
  });
}

function getAncestorLinks(doclet) {
  return helper.getAncestorLinks(data, doclet);
}

function hashToLink(doclet, hash) {
  if (!/^(#.+)/.test(hash)) {
    return hash;
  }

  var url = helper.createLink(doclet);

  url = url.replace(/(#.+|$)/, hash);
  return '<a href="' + url + '">' + hash + '</a>';
}

function needsSignature(doclet) {
  var needsSig = false;

  // function and class definitions always get a signature
  if (doclet.kind === 'function' || doclet.kind === 'class') {
    needsSig = true;
  }
  // typedefs that contain functions get a signature, too
  else if (doclet.kind === 'typedef' && doclet.type && doclet.type.names &&
    doclet.type.names.length) {
    for (var i = 0, l = doclet.type.names.length; i < l; i++) {
      if (doclet.type.names[i].toLowerCase() === 'function') {
        needsSig = true;
        break;
      }
    }
  }

  return needsSig;
}

function addSignatureParams(f) {
  var optionalClass = 'optional';
  var params = helper.getSignatureParams(f, optionalClass);

  f.signature = (f.signature || '') + '(';

  for (var i = 0, l = params.length; i < l; i++) {
    var element = params[i];
    var seperator = (i > 0) ? ', ' : '';

    if (!new RegExp("class=[\"|']"+optionalClass+"[\"|']").test(element)) {
      f.signature += seperator + element;
    } else {
      var regExp = new RegExp("<span class=[\"|']"+optionalClass+"[\"|']>(.*?)<\\/span>", "i");
      f.signature += element.replace(regExp, " $`["+seperator+"$1$']");
    }

  }

  f.signature += ')';
}

function addSignatureReturns(f) {
  if (navOptions.methodHeadingReturns) {
    var returnTypes = helper.getSignatureReturns(f);

    f.signature = '<span class="signature">' + (f.signature || '') + '</span>' + '<span class="type-signature">' + (returnTypes.length ? ' &rarr; {' + returnTypes.join('|') + '}' : '') + '</span>';
  }
  else {
    f.signature = f.signature || '';
  }
}

function addSignatureTypes(f) {
  var types = helper.getSignatureTypes(f);

  f.signature = (f.signature || '') + '<span class="type-signature">' + (types.length ? ' :' + types.join('|') : '') + '</span>';
}

function addAttribs(f) {
  var attribs = helper.getAttribs(f);

  f.attribs = '<span class="type-signature">' + htmlsafe(attribs.length ? '<' + attribs.join(', ') + '> ' : '') + '</span>';
}

function shortenPaths(files, commonPrefix) {
  //	// always use forward slashes
  //	var regexp = new RegExp( '\\\\', 'g' );
  //
  //	var prefix = commonPrefix.toLowerCase().replace( regexp, "/" );
  //
  //	Object.keys( files ).forEach( function ( file ) {
  //		files[file].shortened = files[file]
  //			.resolved
  //			.toLowerCase()
  //			.replace( regexp, '/' )
  //			.replace( prefix, '' );
  //	} );

  Object.keys(files).forEach(function(file) {
    files[file].shortened = files[file].resolved.replace(commonPrefix, '')
    // always use forward slashes
    .replace(/\\/g, '/');
  });


  return files;
}

function getPathFromDoclet(doclet) {
  if (!doclet.meta) {
    return;
  }

  return path.normalize(doclet.meta.path && doclet.meta.path !== 'null' ?
    doclet.meta.path + '/' + doclet.meta.filename :
    doclet.meta.filename);
}

function searchData(html) {
  var startOfContent = html.indexOf("<div class=\"container\">");
  if (startOfContent > 0) {
    var startOfSecondContent = html.indexOf("<div class=\"container\">", startOfContent + 2);
    if (startOfSecondContent > 0) {
      startOfContent = startOfSecondContent;
    }
    html = html.slice(startOfContent);
  }
  var endOfContent = html.indexOf("<span class=\"copyright\">");
  if (endOfContent > 0) {
    html = html.substring(0, endOfContent);
  }
  var stripped = sanitizeHtml(html, {allowedTags: [], allowedAttributes: []});
  stripped = stripped.replace(/\s+/g, ' ');
  return stripped;
}

function generate(docType, title, docs, filename, resolveLinks) {
  resolveLinks = resolveLinks === false ? false : true;

  var docData = {
    title: title,
    docs: docs,
    docType: docType
  };

  var outpath = path.join(outdir, filename),
    html = view.render('container.tmpl', docData);

  if (resolveLinks) {
    html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a>
  }

  if (searchEnabled) {
    searchableDocuments[filename] = {
      "id": filename,
      "title": title,
      "body": searchData(html)
    };
  }

  fs.writeFileSync(outpath, html, 'utf8');
}

function generateSourceFiles(sourceFiles) {
  Object.keys(sourceFiles).forEach(function(file) {
    var source;
    // links are keyed to the shortened path in each doclet's `meta.shortpath` property
    var sourceOutfile = helper.getUniqueFilename(sourceFiles[file].shortened);
    helper.registerLink(sourceFiles[file].shortened, sourceOutfile);

    try {
      source = {
        kind: 'source',
        code: helper.htmlsafe(fs.readFileSync(sourceFiles[file].resolved, 'utf8'))
      };
    } catch (e) {
      handle(e);
    }

    generate('source', 'Source: ' + sourceFiles[file].shortened, [source], sourceOutfile,
      false);
  });
}

/**
 * Look for classes or functions with the same name as modules (which indicates that the module
 * exports only that class or function), then attach the classes or functions to the `module`
 * property of the appropriate module doclets. The name of each class or function is also updated
 * for display purposes. This function mutates the original arrays.
 *
 * @private
 * @param {Array.<module:jsdoc/doclet.Doclet>} doclets - The array of classes and functions to
 * check.
 * @param {Array.<module:jsdoc/doclet.Doclet>} modules - The array of module doclets to search.
 */
function attachModuleSymbols(doclets, modules) {
  var symbols = {};

  // build a lookup table
  doclets.forEach(function(symbol) {
    symbols[symbol.longname] = symbols[symbol.longname] || [];
    symbols[symbol.longname].push(symbol);
  });

  return modules.map(function(module) {
    if (symbols[module.longname]) {
      module.modules = symbols[module.longname]
      // Only show symbols that have a description. Make an exception for classes, because
      // we want to show the constructor-signature heading no matter what.
      .filter(function(symbol) {
        return symbol.description || symbol.kind === 'class';
      })
        .map(function(symbol) {
          symbol = doop(symbol);

          if (symbol.kind === 'class' || symbol.kind === 'function') {
            symbol.name = symbol.name.replace('module:', '(require("') + '"))';
          }

          return symbol;
        });
    }
  });
}

/**
 * Create the navigation sidebar.
 * @param {object} members The members that will be used to create the sidebar.
 * @param {array<object>} members.classes
 * @param {array<object>} members.externals
 * @param {array<object>} members.globals
 * @param {array<object>} members.mixins
 * @param {array<object>} members.interfaces
 * @param {array<object>} members.modules
 * @param {array<object>} members.namespaces
 * @param {array<object>} members.tutorials
 * @param {array<object>} members.events
 * @return {string} The HTML for the navigation sidebar.
 */
function buildNav(members) {

  var seen = {};
  var nav = navigationMaster;
  if (members.modules.length) {

    members.modules.forEach(function(m) {
      if (!hasOwnProp.call(seen, m.longname)) {

        nav.module.members.push(linkto(m.longname, m.longname.replace("module:", "")));
      }
      seen[m.longname] = true;
    });
  }

  if (members.externals.length) {

    members.externals.forEach(function(e) {
      if (!hasOwnProp.call(seen, e.longname)) {

        nav.external.members.push(linkto(e.longname, e.name.replace(/(^"|"$)/g, '')));
      }
      seen[e.longname] = true;
    });
  }

  if (members.classes.length) {

    members.classes.forEach(function(c) {
      if (!hasOwnProp.call(seen, c.longname)) {

        nav.class.members.push(linkto(c.longname, c.longname.replace("module:", "")));
      }
      seen[c.longname] = true;
    });

  }

  if (members.events.length) {

    members.events.forEach(function(e) {
      if (!hasOwnProp.call(seen, e.longname)) {

        nav.event.members.push(linkto(e.longname, e.longname.replace("module:", "")));
      }
      seen[e.longname] = true;
    });

  }

  if (members.namespaces.length) {

    members.namespaces.forEach(function(n) {
      if (!hasOwnProp.call(seen, n.longname)) {

        nav.namespace.members.push(linkto(n.longname, n.longname.replace("module:", "")));
      }
      seen[n.longname] = true;
    });

  }

  if (members.mixins.length) {

    members.mixins.forEach(function(m) {
      if (!hasOwnProp.call(seen, m.longname)) {

        nav.mixin.members.push(linkto(m.longname, m.longname.replace("module:", "")));
      }
      seen[m.longname] = true;
    });

  }

  if (members.interfaces && members.interfaces.length) {

    members.interfaces.forEach(function(m) {
      if (!hasOwnProp.call(seen, m.longname)) {

        nav.interface.members.push(linkto(m.longname, m.longname.replace("module:", "")));
      }
      seen[m.longname] = true;
    });

  }

  if (members.tutorials.length) {

    members.tutorials.forEach(function(t) {

      nav.tutorial.members.push(tutoriallink(t.name));
    });

  }

  if (members.globals.length) {
    members.globals.forEach(function(g) {
      if (g.kind !== 'typedef' && !hasOwnProp.call(seen, g.longname)) {

        nav.global.members.push(linkto(g.longname, g.longname.replace("module:", "")));
      }
      seen[g.longname] = true;
    });

    // even if there are no links, provide a link to the global page.
    if (nav.global.members.length === 0) {
      nav.global.members.push(linkto("global", "Global"));
    }
  }

  var topLevelNav = [];
  _.each(nav, function(entry, name) {
    if (entry.members.length > 0 && name !== "index") {
      topLevelNav.push({
        title: entry.title,
        link: entry.link,
        members: entry.members
      });
    }
  });
  nav.topLevelNav = topLevelNav;
}

/**
 @param {TAFFY} taffyData See <http://taffydb.com/>.
 @param {object} opts
 @param {Tutorial} tutorials
 */
exports.publish = function(taffyData, opts, tutorials) {
  data = taffyData;

  conf['default'] = conf['default'] || {};

  var templatePath = opts.template;
  view = new template.Template(templatePath + '/tmpl');

  // claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness
  // doesn't try to hand them out later
  //	var indexUrl = helper.getUniqueFilename( 'index' );
  // don't call registerLink() on this one! 'index' is also a valid longname

  //	var globalUrl = helper.getUniqueFilename( 'global' );
  helper.registerLink('global', globalUrl);

  // set up templating
  // set up templating
  view.layout = conf['default'].layoutFile ?
    path.getResourcePath(path.dirname(conf['default'].layoutFile),
    path.basename(conf['default'].layoutFile) ) : 'layout.tmpl';

  // set up tutorials for helper
  helper.setTutorials(tutorials);

  data = helper.prune(data);

  var sortOption = navOptions.sort === undefined ? opts.sort : navOptions.sort;
  sortOption = sortOption === undefined ? true : sortOption;
  sortOption = sortOption === true ? 'longname, version, since' : sortOption;
  if (sortOption) {
    data.sort(sortOption);
  }
  helper.addEventListeners(data);

  var sourceFiles = {};
  var sourceFilePaths = [];
  data().each(function(doclet) {
    doclet.attribs = '';

    if (doclet.examples) {
      doclet.examples = doclet.examples.map(function(example) {
        var caption, lang;

        // allow using a markdown parser on the examples captions (surrounded by useless HTML p tags)
        if (example.match(/^\s*(<p>)?<caption>([\s\S]+?)<\/caption>(\s*)([\s\S]+?)(<\/p>)?$/i)) {
          caption = RegExp.$2;
          example = RegExp.$4 + (RegExp.$1 ? '' : RegExp.$5);
        }

        var lang = /{@lang (.*?)}/.exec(example);

        if (lang && lang[1]) {
          example = example.replace(lang[0], "");
          lang = lang[1];

        } else {
          lang = null;
        }

        return {
          caption: caption || '',
          code: example,
          lang: lang || "javascript"
        };
      });
    }
    if (doclet.see) {
      doclet.see.forEach(function(seeItem, i) {
        doclet.see[i] = hashToLink(doclet, seeItem);
      });
    }

    // build a list of source files
    var sourcePath;
    if (doclet.meta) {
      sourcePath = getPathFromDoclet(doclet);
      sourceFiles[sourcePath] = {
        resolved: sourcePath,
        shortened: null
      };

      //Check to see if the array of source file paths already contains
      // the source path, if not then add it
      if (sourceFilePaths.indexOf(sourcePath) === -1) {
          sourceFilePaths.push(sourcePath)
      }
    }
  });

  // update outdir if necessary, then create outdir
  var packageInfo = (find({
    kind: 'package'
  }) || [])[0];
  if (navOptions.disablePackagePath !== true && packageInfo && packageInfo.name) {
    if (packageInfo.version) {
      outdir = path.join(outdir, packageInfo.name, packageInfo.version);
    } else {
      outdir = path.join(outdir, packageInfo.name);
    }
  }
  fs.mkPath(outdir);

	// copy the template's static files to outdir
	var fromDir = path.join( templatePath, 'static' );
	var staticFiles = fs.ls( fromDir, 3 );

	staticFiles.forEach( function ( fileName ) {
		var toFile = fileName.replace( fromDir, outdir );
		var toDir = fs.toDir( toFile );
		fs.mkPath( toDir );
		fs.copyFileSync( fileName, '', toFile );
	} );

    // copy user-specified static files to outdir
    var staticFilePaths;
    var staticFileFilter;
    var staticFileScanner;
    if (conf.default.staticFiles) {
        // The canonical property name is `include`. We accept `paths` for backwards compatibility
        // with a bug in JSDoc 3.2.x.
        staticFilePaths = conf.default.staticFiles.include ||
            conf.default.staticFiles.paths ||
            [];
        staticFileFilter = new (require('jsdoc/src/filter')).Filter(conf.default.staticFiles);
        staticFileScanner = new (require('jsdoc/src/scanner')).Scanner();

        staticFilePaths.forEach(function(filePath) {
            var extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter);

            extraStaticFiles.forEach(function(fileName) {
                var sourcePath = fs.toDir(filePath);
                var toDir = fs.toDir( fileName.replace(sourcePath, outdir) );
                fs.mkPath(toDir);
                fs.copyFileSync(fileName, toDir);
            });
        });
    }

  if (sourceFilePaths.length) {
    var payload = navOptions.sourceRootPath;
    if (!payload) {
      payload = path.commonPrefix(sourceFilePaths);
    }
    sourceFiles = shortenPaths(sourceFiles, payload);
  }
  data().each(function(doclet) {
    var url = helper.createLink(doclet);
    helper.registerLink(doclet.longname, url);

    // add a shortened version of the full path
    var docletPath;
    if (doclet.meta) {
      docletPath = getPathFromDoclet(doclet);
      if (!_.isEmpty(sourceFiles[docletPath])) {
        docletPath = sourceFiles[docletPath].shortened;
        if (docletPath) {
          doclet.meta.shortpath = docletPath;
        }
      }
    }
  });

  data().each(function(doclet) {
    var url = helper.longnameToUrl[doclet.longname];

    if (url.indexOf('#') > -1) {
      doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop();
    } else {
      doclet.id = doclet.name;
    }

    if (needsSignature(doclet)) {
      addSignatureParams(doclet);
      addSignatureReturns(doclet);
      addAttribs(doclet);
    }
  });

  // do this after the urls have all been generated
  data().each(function(doclet) {
    doclet.ancestors = getAncestorLinks(doclet);

    if (doclet.kind === 'member') {
      addSignatureTypes(doclet);
      addAttribs(doclet);
    }

    if (doclet.kind === 'constant') {
      addSignatureTypes(doclet);
      addAttribs(doclet);
      doclet.kind = 'member';
    }
  });

  var members = helper.getMembers(data);
  members.tutorials = tutorials.children;

  // add template helpers
  view.find = find;
  view.linkto = linkto;
  view.resolveAuthorLinks = resolveAuthorLinks;
  view.tutoriallink = tutoriallink;
  view.htmlsafe = htmlsafe;
  view.moment = moment;

  // once for all
  buildNav(members);
  view.nav = navigationMaster;
  view.navOptions = navOptions;
  attachModuleSymbols(find({
      kind: ['class', 'function'],
      longname: {
        left: 'module:'
      }
    }),
    members.modules);

  // only output pretty-printed source files if requested; do this before generating any other
  // pages, so the other pages can link to the source files
  if (navOptions.outputSourceFiles) {
    generateSourceFiles(sourceFiles);
  }

  if (members.globals.length) {
    generate('global', 'Global', [{
      kind: 'globalobj'
    }], globalUrl);
  }

  // some browsers can't make the dropdown work
  if (view.nav.module && view.nav.module.members.length) {
    generate('module', view.nav.module.title, [{
      kind: 'sectionIndex',
      contents: view.nav.module
    }], navigationMaster.module.link);
  }

  if (view.nav.class && view.nav.class.members.length) {
    generate('class', view.nav.class.title, [{
      kind: 'sectionIndex',
      contents: view.nav.class
    }], navigationMaster.class.link);
  }

  if (view.nav.namespace && view.nav.namespace.members.length) {
    generate('namespace', view.nav.namespace.title, [{
      kind: 'sectionIndex',
      contents: view.nav.namespace
    }], navigationMaster.namespace.link);
  }

  if (view.nav.mixin && view.nav.mixin.members.length) {
    generate('mixin', view.nav.mixin.title, [{
      kind: 'sectionIndex',
      contents: view.nav.mixin
    }], navigationMaster.mixin.link);
  }

  if (view.nav.interface && view.nav.interface.members.length) {
    generate('interface', view.nav.interface.title, [{
      kind: 'sectionIndex',
      contents: view.nav.interface
    }], navigationMaster.interface.link);
  }

  if (view.nav.external && view.nav.external.members.length) {
    generate('external', view.nav.external.title, [{
      kind: 'sectionIndex',
      contents: view.nav.external
    }], navigationMaster.external.link);
  }

  if (view.nav.tutorial && view.nav.tutorial.members.length) {
    generate('tutorial', view.nav.tutorial.title, [{
      kind: 'sectionIndex',
      contents: view.nav.tutorial
    }], navigationMaster.tutorial.link);
  }

  // index page displays information from package.json and lists files
  var files = find({
      kind: 'file'
    }),
    packages = find({
      kind: 'package'
    });

  generate('index', 'Index',
    packages.concat(
      [{
        kind: 'mainpage',
        readme: opts.readme,
        longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'
      }]
    ).concat(files),
    indexUrl);

  // set up the lists that we'll use to generate pages
  var classes = taffy(members.classes);
  var modules = taffy(members.modules);
  var namespaces = taffy(members.namespaces);
  var mixins = taffy(members.mixins);
  var interfaces = taffy(members.interfaces);
  var externals = taffy(members.externals);

  for (var longname in helper.longnameToUrl) {
    if (hasOwnProp.call(helper.longnameToUrl, longname)) {
      var myClasses = helper.find(classes, {
        longname: longname
      });
      if (myClasses.length) {
        generate('class', 'Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]);
      }

      var myModules = helper.find(modules, {
        longname: longname
      });
      if (myModules.length) {
        generate('module', 'Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname]);
      }

      var myNamespaces = helper.find(namespaces, {
        longname: longname
      });
      if (myNamespaces.length) {
        generate('namespace', 'Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]);
      }

      var myMixins = helper.find(mixins, {
        longname: longname
      });
      if (myMixins.length) {
        generate('mixin', 'Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]);
      }

      var myInterfaces = helper.find(interfaces, {
        longname: longname
      });
      if (myInterfaces.length) {
        generate('interface', 'Interface: ' + myInterfaces[0].name, myInterfaces, helper.longnameToUrl[longname]);
      }

      var myExternals = helper.find(externals, {
        longname: longname
      });
      if (myExternals.length) {
        generate('external', 'External: ' + myExternals[0].name, myExternals, helper.longnameToUrl[longname]);
      }
    }
  }

  // TODO: move the tutorial functions to templateHelper.js
  function generateTutorial(title, tutorial, filename) {
    var tutorialData = {
      title: title,
      header: tutorial.title,
      content: tutorial.parse(),
      children: tutorial.children,
      docs: null
    };

    var tutorialPath = path.join(outdir, filename),
      html = view.render('tutorial.tmpl', tutorialData);

    // yes, you can use {@link} in tutorials too!
    html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a>

    if (searchEnabled) {
      searchableDocuments[filename] = {
        "id": filename,
        "title": title,
        "body": searchData(html)
      };
    }

    fs.writeFileSync(tutorialPath, html, 'utf8');
  }

  // tutorials can have only one parent so there is no risk for loops
  function saveChildren(node) {
    node.children.forEach(function(child) {
      generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name));
      saveChildren(child);
    });
  }

  function generateQuickTextSearch(templatePath, searchableDocuments, navOptions) {
      var data = {
          searchableDocuments: JSON.stringify(searchableDocuments),
          navOptions: navOptions
      };

      var tmplString = fs.readFileSync(templatePath + "/quicksearch.tmpl").toString(),
            tmpl = _.template(tmplString);

      var html = tmpl(data),
            outpath = path.join(outdir, "quicksearch.html");

      fs.writeFileSync(outpath, html, "utf8");
  }

  saveChildren(tutorials);

  if (searchEnabled) {
      generateQuickTextSearch(templatePath + '/tmpl', searchableDocuments, navOptions);
  }
};


================================================
FILE: lerna.json
================================================
{
  "lerna": "2.11.0",
  "npmClient": "yarn",
  "useWorkspaces": true,
  "packages": [
    "packages/*"
  ],
  "version": "2.0.0"
}


================================================
FILE: package.json
================================================
{
  "private": true,
  "devDependencies": {
    "coveralls": "^3.0.1",
    "eslint": "^4.19.1",
    "eslint-config-airbnb": "^16.1.0",
    "eslint-config-prettier": "^2.9.0",
    "eslint-plugin-import": "^2.11.0",
    "eslint-plugin-jsx-a11y": "^6.0.3",
    "eslint-plugin-prettier": "^2.6.0",
    "eslint-plugin-react": "^7.8.1",
    "gh-pages": "^1.1.0",
    "ink-docstrap": "^1.3.2",
    "jsdoc": "^3.5.5",
    "koa": "^2.13.0",
    "koa-bodyparser": "^4.3.0",
    "koa-router": "^9.1.0",
    "lerna": "^2.11.0",
    "mocha": "^5.1.1",
    "mocha-lcov-reporter": "^1.3.0",
    "mochify": "^5.6.1",
    "nyc": "^11.8.0",
    "prettier": "^1.12.1",
    "showdown": "^1.8.6",
    "sinon": "^5.0.7"
  },
  "scripts": {
    "bootstrap": "lerna bootstrap",
    "lint": "lerna exec yarn lint",
    "pretest": "yarn lint",
    "test:node:coverage": "nyc --report-dir build/coverage/ --reporter=html --reporter=text lerna exec yarn test:node",
    "test:browser": "lerna exec yarn test:browser",
    "test": "yarn test:node:coverage && yarn test:browser",
    "format": "lerna exec yarn format",
    "clean": "rm -fr build && lerna exec yarn clean",
    "generate-docs": "./scripts/generate-docs.sh",
    "deploy-docs": "gh-pages -d build/docs",
    "travis-deploy-github-pages": "gh-pages -r \"https://${GH_TOKEN}@github.com/yaorg/node-measured.git\" -d build/docs",
    "coverage": "nyc report --reporter=text-lcov | coveralls"
  },
  "repository": {
    "url": "git://github.com/yaorg/node-measured.git"
  },
  "homepage": "https://yaorg.github.io/node-measured/",
  "license": "MIT",
  "workspaces": [
    "packages/*"
  ]
}


================================================
FILE: packages/measured-core/README.md
================================================
# Measured Core

The core measured library that has the Metric interfaces and implementations.

[![npm](https://img.shields.io/npm/v/measured-core.svg)](https://www.npmjs.com/package/measured-core) 

## Install

```
npm install measured-core
```

## What is in this package

### Metric Implemenations

The core library has the following metrics classes:

#### [Gauge](https://yaorg.github.io/node-measured/packages/measured-core/Gauge.html)
Values that can be read instantly via a supplied call back.

#### [SettableGauge](https://yaorg.github.io/node-measured/packages/measured-core/SettableGauge.html)
Just like a Gauge but its value is set directly rather than supplied by a callback.

#### [CachedGauge](https://yaorg.github.io/node-measured/packages/measured-core/CachedGauge.html)
Like a mix of the regular and settable Gauge it takes a call back that returns a promise that will resolve the cached value and an interval that it should call the callback on to update its cached value.

#### [Counter](https://yaorg.github.io/node-measured/packages/measured-core/Counter.html)
Counters are things that increment or decrement.

#### [Timer](https://yaorg.github.io/node-measured/packages/measured-core/Timer.html)
Timers are a combination of Meters and Histograms. They measure the rate as well as distribution of scalar events.

#### [Histogram](https://yaorg.github.io/node-measured/packages/measured-core/Histogram.html)
Keeps a reservoir of statistically relevant values to explore their distribution.

#### [Meter](https://yaorg.github.io/node-measured/packages/measured-core/Meter.html)
Things that are measured as events / interval.

### Registry

The core library comes with a basic registry class 

#### [Collection](https://yaorg.github.io/node-measured/packages/measured-core/Collection.html)

that is not aware of dimensions / tags and leaves reporting up to you.

#### See the [measured-reporting](../measured-reporting/) module for more advanced and featured registries.

### Other

See The [measured-core](https://yaorg.github.io/node-measured/packages/measured-core/module-measured-core.html) modules for the full list of exports for require('measured-core').

## Usage

**Step 1:** Add measurements to your code. For example, lets track the
requests/sec of a http server:

```js
var http  = require('http');
var stats = require('measured').createCollection();

http.createServer(function(req, res) {
  stats.meter('requestsPerSecond').mark();
  res.end('Thanks');
}).listen(3000);
```

**Step 2:** Show the collected measurements (more advanced examples follow later):

```js
setInterval(function() {
  console.log(stats.toJSON());
}, 1000);
```

This will output something like this every second:

```
{ requestsPerSecond:
   { mean: 1710.2180279856818,
     count: 10511,
     'currentRate': 1941.4893498239829,
     '1MinuteRate': 168.08263156623656,
     '5MinuteRate': 34.74630977619571,
     '15MinuteRate': 11.646507524106095 } }
```

**Step 3:** Aggregate the data into your backend of choice.
Here are a few time series data aggregators.
- [Graphite](http://graphite.wikidot.com/)
    - A free and open source, self hosted and managed solution for time series data.
- [SignalFx](https://signalfx.com/)
    - An enterprise SASS offering for time series data.
- [Datadog](https://www.datadoghq.com/)
    - An enterprise SASS offering for time series data.


================================================
FILE: packages/measured-core/lib/Collection.js
================================================
const Optional = require('optional-js');
const Counter = require('./metrics/Counter');
const Gauge = require('./metrics/Gauge');
const SettableGauge = require('./metrics/SettableGauge');
const CachedGauge = require('./metrics/CachedGauge');
const Histogram = require('./metrics/Histogram');
const Meter = require('./metrics/Meter');
const Timer = require('./metrics/Timer');
const { MetricTypes } = require('./metrics/Metric');

/**
 * A Simple collection that stores names and a {@link Metric} instances with a few convenience methods for
 * creating / registering and then gathering all data the registered metrics.
 * @example
 * var { Collection } = require('measured');
 * const collection = new Collection('node-process-metrics');
 * const gauge = collection.gauge('node.process.heap_used', () => {
 *    return process.memoryUsage().heapUsed;
 * });
 */
class Collection {
  /**
   * Creates a named collection of metrics
   * @param {string} [name] The name to use for this collection.
   */
  constructor(name) {
    this.name = name;

    /**
     * internal map of metric name to {@link Metric}
     * @type {Object.<string, Metric>}
     * @private
     */
    this._metrics = {};
  }

  /**
   * register a metric that was created outside the provided convenience methods of this collection
   * @param name The metric name
   * @param metric The {@link Metric} implementation
   * @example
   * var { Collection, Gauge } = require('measured');
   * const collection = new Collection('node-process-metrics');
   * const gauge = new Gauge(() => {
   *    return process.memoryUsage().heapUsed;
   * });
   * collection.register('node.process.heap_used', gauge);
   */
  register(name, metric) {
    this._metrics[name] = metric;
  }

  /**
   * Fetches the data/values from all registered metrics
   * @return {Object} The combined JSON object
   */
  toJSON() {
    const json = {};

    Object.keys(this._metrics).forEach(metric => {
      if (Object.prototype.hasOwnProperty.call(this._metrics, metric)) {
        json[metric] = this._metrics[metric].toJSON();
      }
    });

    if (!this.name) {
      return json;
    }

    const wrapper = {};
    wrapper[this.name] = json;

    return wrapper;
  }

  /**
   * Gets or creates and registers a {@link Gauge}
   * @param {string} name The metric name
   * @param {function} readFn See {@link Gauge}
   * @return {Gauge}
   */
  gauge(name, readFn) {
    this._validateName(name);

    let gauge;
    this._getMetricForNameAndType(name, MetricTypes.GAUGE).ifPresentOrElse(
      registeredMetric => {
        gauge = registeredMetric;
      },
      () => {
        gauge = new Gauge(readFn);
        this.register(name, gauge);
      }
    );
    return gauge;
  }

  /**
   * Gets or creates and registers a {@link Counter}
   * @param {string} name The metric name
   * @param {CounterProperties} [properties] See {@link CounterProperties}
   * @return {Counter}
   */
  counter(name, properties) {
    this._validateName(name);

    let counter;
    this._getMetricForNameAndType(name, MetricTypes.COUNTER).ifPresentOrElse(
      registeredMetric => {
        counter = registeredMetric;
      },
      () => {
        counter = new Counter(properties);
        this.register(name, counter);
      }
    );
    return counter;
  }

  /**
   * Gets or creates and registers a {@link Histogram}
   * @param {string} name The metric name
   * @param {HistogramProperties} [properties] See {@link HistogramProperties}
   * @return {Histogram}
   */
  histogram(name, properties) {
    this._validateName(name);

    let histogram;
    this._getMetricForNameAndType(name, MetricTypes.HISTOGRAM).ifPresentOrElse(
      registeredMetric => {
        histogram = registeredMetric;
      },
      () => {
        histogram = new Histogram(properties);
        this.register(name, histogram);
      }
    );
    return histogram;
  }

  /**
   * Gets or creates and registers a {@link Timer}
   * @param {string} name The metric name
   * @param {TimerProperties} [properties] See {@link TimerProperties}
   * @return {Timer}
   */
  timer(name, properties) {
    this._validateName(name);

    let timer;
    this._getMetricForNameAndType(name, MetricTypes.TIMER).ifPresentOrElse(
      registeredMetric => {
        timer = registeredMetric;
      },
      () => {
        timer = new Timer(properties);
        this.register(name, timer);
      }
    );
    return timer;
  }

  /**
   * Gets or creates and registers a {@link Meter}
   * @param {string} name The metric name
   * @param {MeterProperties} [properties] See {@link MeterProperties}
   * @return {Meter}
   */
  meter(name, properties) {
    this._validateName(name);

    let meter;
    this._getMetricForNameAndType(name, MetricTypes.METER).ifPresentOrElse(
      registeredMetric => {
        meter = registeredMetric;
      },
      () => {
        meter = new Meter(properties);
        this.register(name, meter);
      }
    );
    return meter;
  }

  /**
   * Gets or creates and registers a {@link SettableGauge}
   * @param {string} name The metric name
   * @param {SettableGaugeProperties} [properties] See {@link SettableGaugeProperties}
   * @return {SettableGauge}
   */
  settableGauge(name, properties) {
    this._validateName(name);

    let settableGauge;
    this._getMetricForNameAndType(name, MetricTypes.GAUGE).ifPresentOrElse(
      registeredMetric => {
        settableGauge = registeredMetric;
      },
      () => {
        settableGauge = new SettableGauge(properties);
        this.register(name, settableGauge);
      }
    );
    return settableGauge;
  }

  /**
   * Gets or creates and registers a {@link SettableGauge}
   * @param {string} name The metric name
   * @param {function} valueProducingPromiseCallback A function that returns a promise than when
   * resolved supplies the value that should be cached in this gauge.
   * @param {number} updateIntervalInSeconds How often the cached gauge should update it's value.
   * @return {CachedGauge}
   */
  cachedGauge(name, valueProducingPromiseCallback, updateIntervalInSeconds) {
    this._validateName(name);

    let cachedGauge;
    this._getMetricForNameAndType(name, MetricTypes.GAUGE).ifPresentOrElse(
      registeredMetric => {
        cachedGauge = registeredMetric;
      },
      () => {
        cachedGauge = new CachedGauge(valueProducingPromiseCallback, updateIntervalInSeconds);
        this.register(name, cachedGauge);
      }
    );
    return cachedGauge;
  }

  /**
   * Checks the registry for a metric with a given name and type, if it exists in the registry as a
   * different type an error is thrown.
   * @param {string} name The metric name
   * @param {string} requestedType The metric type
   * @return {Optional<Metric>}
   * @private
   */
  _getMetricForNameAndType(name, requestedType) {
    if (this._metrics[name]) {
      const metric = this._metrics[name];
      const actualType = metric.getType();
      if (requestedType !== actualType) {
        throw new Error(
          `You requested a metric of type: ${requestedType} with name: ${name}, but it exists in the registry as type: ${actualType}`
        );
      }
      return Optional.of(metric);
    }
    return Optional.empty();
  }

  /**
   * Validates that the provided name is valid.
   *
   * @param name The provided metric name param.
   * @private
   */
  _validateName(name) {
    if (!name || typeof name !== 'string') {
      throw new Error('You must supply a metric name');
    }
  }

  /**
   * Calls end on all metrics in the registry that support end()
   */
  end() {
    const metrics = this._metrics;
    Object.keys(metrics).forEach(name => {
      const metric = metrics[name];
      if (metric.end) {
        metric.end();
      }
    });
  }
}

module.exports = Collection;


================================================
FILE: packages/measured-core/lib/index.js
================================================
const Collection = require('./Collection');
const Counter = require('./metrics/Counter');
const Gauge = require('./metrics/Gauge');
const SettableGauge = require('./metrics/SettableGauge');
const CachedGauge = require('./metrics/CachedGauge');
const Histogram = require('./metrics/Histogram');
const Meter = require('./metrics/Meter');
const NoOpMeter = require('./metrics/NoOpMeter');
const Timer = require('./metrics/Timer');
const BinaryHeap = require('./util/BinaryHeap');
const ExponentiallyDecayingSample = require('./util/ExponentiallyDecayingSample');
const ExponentiallyMovingWeightedAverage = require('./util/ExponentiallyMovingWeightedAverage');
const Stopwatch = require('./util/Stopwatch');
const units = require('./util/units');
const { MetricTypes } = require('./metrics/Metric');
const metricValidators = require('./validators/metricValidators');

/**
 * The main measured-core module that is referenced when require('measured-core') is used.
 * @module measured-core
 */
module.exports = {
  /**
   * See {@link Collection}
   * @type {Collection}
   */
  Collection,

  /**
   * See {@link Counter}
   * @type {Counter}
   */
  Counter,

  /**
   * See {@link Gauge}
   * @type {Gauge}
   */
  Gauge,

  /**
   * See {@link SettableGauge}
   * @type {SettableGauge}
   */
  SettableGauge,

  /**
   * See {@link CachedGauge}
   * @type {CachedGauge}
   */
  CachedGauge,

  /**
   * See {@link Histogram}
   * @type {Histogram}
   */
  Histogram,

  /**
   * See {@link Meter}
   * @type {Meter}
   */
  Meter,

  /**
   * See {@link NoOpMeter}
   * @type {NoOpMeter}
   */
  NoOpMeter,

  /**
   * See {@link Timer}
   * @type {Timer}
   */
  Timer,

  /**
   * See {@link BinaryHeap}
   * @type {BinaryHeap}
   */
  BinaryHeap,

  /**
   * See {@link ExponentiallyDecayingSample}
   * @type {ExponentiallyDecayingSample}
   */
  ExponentiallyDecayingSample,

  /**
   * See {@link ExponentiallyMovingWeightedAverage}
   * @type {ExponentiallyMovingWeightedAverage}
   */
  ExponentiallyMovingWeightedAverage,

  /**
   * See {@link Stopwatch}
   * @type {Stopwatch}
   */
  Stopwatch,

  /**
   * See {@link MetricTypes}
   * @type {MetricTypes}
   */
  MetricTypes,

  /**
   * See {@link units}
   * @type {units}
   */
  units,

  /**
   * See {@link units}
   * @type {units}
   */
  TimeUnits: units,

  /**
   * See {@link module:metricValidators}
   * @type {Object.<string, function>}
   */
  metricValidators,

  /**
   * Creates a named collection. See {@link Collection} for more details
   *
   * @param name The name for the collection
   * @return {Collection}
   */
  createCollection: name => {
    return new Collection(name);
  }
};


================================================
FILE: packages/measured-core/lib/metrics/CachedGauge.js
================================================
const { MetricTypes } = require('./Metric');
const TimeUnits = require('../util/units');

/**
 * A Cached Gauge takes a function that returns a promise that resolves a
 * value that should be cached and updated on a given interval.
 *
 * toJSON() will return the currently cached value.
 *
 * @example
 * const cpuAverageCachedGauge = new CachedGauge(() => {
 *     return new Promise(resolve => {
 *       //Grab first CPU Measure
 *       const startMeasure = cpuAverage();
 *       setTimeout(() => {
 *         //Grab second Measure
 *         const endMeasure = cpuAverage();
 *         const percentageCPU = calculateCpuUsagePercent(startMeasure, endMeasure);
 *         resolve(percentageCPU);
 *       }, sampleTimeInSeconds);
 *     });
 *   }, updateIntervalInSeconds);
 *
 * @implements {Metric}
 */
class CachedGauge {
  /**
   * @param {function} valueProducingPromiseCallback A function that returns a promise than when
   * resolved supplies the value that should be cached in this gauge.
   * @param {number} updateIntervalInSeconds How often the cached gauge should update it's value.
   * @param {number} [timeUnitOverride] by default this function takes updateIntervalInSeconds and multiplies it by TimeUnits.SECONDS (1000),
   * You can override it here.
   */
  constructor(valueProducingPromiseCallback, updateIntervalInSeconds, timeUnitOverride) {
    const timeUnit = timeUnitOverride || TimeUnits.SECONDS;

    this._valueProducingPromiseCallback = valueProducingPromiseCallback;
    this._value = 0;
    this._updateValue();
    this._interval = setInterval(() => {
      this._updateValue();
    }, updateIntervalInSeconds * timeUnit);
  }

  /**
   * Calls the promise producing callback and sets the value when it gets resolved.
   * @private
   */
  _updateValue() {
    this._valueProducingPromiseCallback().then(value => {
      this._value = value;
    });
  }

  /**
   * @return {number} Gauges directly return the value which should be a number.
   */
  toJSON() {
    return this._value;
  }

  /**
   * The type of the Metric Impl. {@link MetricTypes}.
   * @return {string} The type of the Metric Impl.
   */
  getType() {
    return MetricTypes.GAUGE;
  }

  /**
   * Clears the interval, so that it doesn't keep any processes alive.
   */
  end() {
    clearInterval(this._interval);
    this._interval = null;
  }
}

module.exports = CachedGauge;


================================================
FILE: packages/measured-core/lib/metrics/Counter.js
================================================
const { MetricTypes } = require('./Metric');

/**
 * Counters are things that increment or decrement
 * @implements {Metric}
 * @example
 * var Measured = require('measured')
 * var activeUploads = new Measured.Counter();
 * http.createServer(function(req, res) {
 *    activeUploads.inc();
 *    req.on('end', function() {
 *         activeUploads.dec();
 *    });
 * });
 */
class Counter {
  /**
   * @param {CounterProperties} [properties] see {@link CounterProperties}
   */
  constructor(properties) {
    properties = properties || {};

    this._count = properties.count || 0;
  }

  /**
   * Counters directly return their currently value.
   * @return {number}
   */
  toJSON() {
    return this._count;
  }

  /**
   * Increments the counter.
   * @param {number} n Increment the counter by n. Defaults to 1.
   */
  inc(n) {
    this._count += arguments.length ? n : 1;
  }

  /**
   * Decrements the counter
   * @param {number} n Decrement the counter by n. Defaults to 1.
   */
  dec(n) {
    this._count -= arguments.length ? n : 1;
  }

  /**
   * Resets the counter back to count Defaults to 0.
   * @param {number} count Resets the counter back to count Defaults to 0.
   */
  reset(count) {
    this._count = count || 0;
  }

  /**
   * The type of the Metric Impl. {@link MetricTypes}.
   * @return {string} The type of the Metric Impl.
   */
  getType() {
    return MetricTypes.COUNTER;
  }
}

module.exports = Counter;

/**
 * Properties that can be supplied to the constructor of a {@link Counter}
 *
 * @interface CounterProperties
 * @typedef CounterProperties
 * @type {Object}
 * @property {number} count An initial count for the counter. Defaults to 0.
 * @example
 * // Creates a counter that starts at 5.
 * const counter = new Counter({ count: 5 })
 */


================================================
FILE: packages/measured-core/lib/metrics/Gauge.js
================================================
const { MetricTypes } = require('./Metric');

/**
 * Values that can be read instantly
 * @implements {Metric}
 * @example
 * var Measured = require('measured')
 * var gauge = new Measured.Gauge(function() {
 *     return process.memoryUsage().rss;
 * });
 */
class Gauge {
  /**
   * @param {function} readFn A function that returns the numeric value for this gauge.
   */
  constructor(readFn) {
    this._readFn = readFn;
  }

  /**
   * @return {number} Gauges directly return the value from the callback which should be a number.
   */
  toJSON() {
    return this._readFn();
  }

  /**
   * The type of the Metric Impl. {@link MetricTypes}.
   * @return {string} The type of the Metric Impl.
   */
  getType() {
    return MetricTypes.GAUGE;
  }
}

module.exports = Gauge;


================================================
FILE: packages/measured-core/lib/metrics/Histogram.js
================================================
const { MetricTypes } = require('./Metric');
const binarySearch = require('binary-search');
const EDS = require('../util/ExponentiallyDecayingSample');

/**
 * Keeps a reservoir of statistically relevant values biased towards the last 5 minutes to explore their distribution.
 * @implements {Metric}
 * @example
 * var Measured = require('measured')
 * var histogram = new Measured.Histogram();
 * http.createServer(function(req, res) {
 *   if (req.headers['content-length']) {
 *     histogram.update(parseInt(req.headers['content-length'], 10));
 *   }
 * });
 */
class Histogram {
  /**
   @param {HistogramProperties} [properties] see {@link HistogramProperties}.
   */
  constructor(properties) {
    this._properties = properties || {};
    this._initializeState();
  }

  _initializeState() {
    this._sample = this._properties.sample || new EDS();
    this._percentilesMethod = this._properties.percentilesMethod || this._percentiles;
    this._min = null;
    this._max = null;
    this._count = 0;
    this._sum = 0;

    // These are for the Welford algorithm for calculating running constiance
    // without floating-point doom.
    this._constianceM = 0;
    this._constianceS = 0;
  }

  /**
   * Pushes value into the sample. timestamp defaults to Date.now().
   * @param {number} value
   */
  update(value) {
    this._count++;
    this._sum += value;

    this._sample.update(value);
    this._updateMin(value);
    this._updateMax(value);
    this._updateVariance(value);
  }

  _percentiles(percentiles) {
    const values = this._sample.toArray().sort((a, b) => {
      return a === b ? 0 : a - b;
    });

    const results = {};

    let i, percentile, pos, lower, upper;
    for (i = 0; i < percentiles.length; i++) {
      percentile = percentiles[i];
      if (values.length) {
        pos = percentile * (values.length + 1);
        if (pos < 1) {
          results[percentile] = values[0];
        } else if (pos >= values.length) {
          results[percentile] = values[values.length - 1];
        } else {
          lower = values[Math.floor(pos) - 1];
          upper = values[Math.ceil(pos) - 1];
          results[percentile] = lower + (pos - Math.floor(pos)) * (upper - lower);
        }
      } else {
        results[percentile] = null;
      }
    }

    return results;
  }

  weightedPercentiles(percentiles) {
    const values = this._sample.toArrayWithWeights().sort((a, b) => {
      return a.value === b.value ? 0 : a.value - b.value;
    });

    const sumWeight = values.reduce((sum, sample) => {
      return sum + sample.priority;
    }, 0);

    const normWeights = values.map(value => {
      return value.priority / sumWeight;
    });

    const quantiles = [0];
    let i;
    for (i = 1; i < values.length; i++) {
      quantiles[i] = quantiles[i - 1] + normWeights[i - 1];
    }

    function gt(a, b) {
      return a - b;
    }

    const results = {};
    let percentile, pos;
    for (i = 0; i < percentiles.length; i++) {
      percentile = percentiles[i];
      if (values.length) {
        pos = binarySearch(quantiles, percentile, gt);
        if (pos < 0) {
          results[percentile] = values[-pos - 1 - 1].value;
        } else if (pos < 1) {
          results[percentile] = values[0].value;
        } else if (pos >= values.length) {
          results[percentile] = values[values.length - 1].value;
        }
      } else {
        results[percentile] = null;
      }
    }
    return results;
  }

  /**
   * Resets all values. Histograms initialized with custom options will be reset to the default settings (patch welcome).
   */
  reset() {
    // while this is technically a bug?, copying existing logic to maintain current api,
    // TODO reset should reset the sample, not override it with a new EDS()
    this._properties.sample = new EDS();

    this._initializeState();
  }

  /**
   * Checks whether the histogram contains values.
   * @return {boolean} Whether the histogram contains values.
   */
  hasValues() {
    return this._count > 0;
  }

  /**
   * @return {HistogramData}
   */
  toJSON() {
    const percentiles = this._percentilesMethod([0.5, 0.75, 0.95, 0.99, 0.999]);

    return {
      min: this._min,
      max: this._max,
      sum: this._sum,
      variance: this._calculateVariance(),
      mean: this._calculateMean(),
      stddev: this._calculateStddev(),
      count: this._count,
      median: percentiles[0.5],
      p75: percentiles[0.75],
      p95: percentiles[0.95],
      p99: percentiles[0.99],
      p999: percentiles[0.999]
    };
  }

  _updateMin(value) {
    if (this._min === null || value < this._min) {
      this._min = value;
    }
  }

  _updateMax(value) {
    if (this._max === null || value > this._max) {
      this._max = value;
    }
  }

  _updateVariance(value) {
    if (this._count === 1) {
      this._constianceM = value;
      return value;
    }

    const oldM = this._constianceM;

    this._constianceM += (value - oldM) / this._count;
    this._constianceS += (value - oldM) * (value - this._constianceM);

    // TODO is this right, above it returns in the if statement but does nothing but update internal state for the else case?
    return undefined;
  }

  /**
   *
   * @return {number|null}
   * @private
   */
  _calculateMean() {
    return this._count === 0 ? 0 : this._sum / this._count;
  }

  /**
   * @return {number|null}
   * @private
   */
  _calculateVariance() {
    return this._count <= 1 ? null : this._constianceS / (this._count - 1);
  }

  /**
   * @return {number|null}
   * @private
   */
  _calculateStddev() {
    return this._count < 1 ? null : Math.sqrt(this._calculateVariance());
  }

  /**
   * The type of the Metric Impl. {@link MetricTypes}.
   * @return {string} The type of the Metric Impl.
   */
  getType() {
    return MetricTypes.HISTOGRAM;
  }
}

module.exports = Histogram;

/**
 * Properties to create a {@link Histogram} with.
 *
 * @interface HistogramProperties
 * @typedef HistogramProperties
 * @type {Object}
 * @property {object} sample The sample reservoir to use. Defaults to an ExponentiallyDecayingSample.
 */

/**
 * The data returned from Histogram::toJSON()
 * @interface HistogramData
 * @typedef HistogramData
 * @typedef {object}
 * @property {number|null} min The lowest observed value.
 * @property {number|null} max The highest observed value.
 * @property {number|null} sum The sum of all observed values.
 * @property {number|null} variance The variance of all observed values.
 * @property {number|null} mean The average of all observed values.
 * @property {number|null} stddev The stddev of all observed values.
 * @property {number} count The number of observed values.
 * @property {number} median 50% of all values in the resevoir are at or below this value.
 * @property {number} p75 See median, 75% percentile.
 * @property {number} p95 See median, 95% percentile.
 * @property {number} p99 See median, 99% percentile.
 * @property {number} p999 See median, 99.9% percentile.
 */


================================================
FILE: packages/measured-core/lib/metrics/Meter.js
================================================
const { MetricTypes } = require('./Metric');
const units = require('../util/units');
const EWMA = require('../util/ExponentiallyMovingWeightedAverage');

const RATE_UNIT = units.SECONDS;
const TICK_INTERVAL = 5 * units.SECONDS;

/**
 * Things that are measured as events / interval.
 * @implements {Metric}
 * @example
 * var Measured = require('measured')
 * var meter = new Measured.Meter();
 * http.createServer(function(req, res) {
 *     meter.mark();
 * });
 */
class Meter {
  /**
   * @param {MeterProperties} [properties] see {@link MeterProperties}.
   */
  constructor(properties) {
    this._properties = properties || {};
    this._initializeState();

    if (!this._properties.keepAlive) {
      this.unref();
    }
  }

  /**
   * Initializes the state of this Metric
   * @private
   */
  _initializeState() {
    this._rateUnit = this._properties.rateUnit || RATE_UNIT;
    this._tickInterval = this._properties.tickInterval || TICK_INTERVAL;
    if (this._properties.getTime) {
      this._getTime = this._properties.getTime;
    }

    this._m1Rate = this._properties.m1Rate || new EWMA(units.MINUTES, this._tickInterval);
    this._m5Rate = this._properties.m5Rate || new EWMA(5 * units.MINUTES, this._tickInterval);
    this._m15Rate = this._properties.m15Rate || new EWMA(15 * units.MINUTES, this._tickInterval);
    this._count = 0;
    this._currentSum = 0;
    this._startTime = this._getTime();
    this._lastToJSON = this._getTime();
    this._interval = setInterval(this._tick.bind(this), TICK_INTERVAL);
  }

  /**
   * Register n events as having just occured. Defaults to 1.
   * @param {number} [n]
   */
  mark(n) {
    if (!this._interval) {
      this.start();
    }

    n = n || 1;

    this._count += n;
    this._currentSum += n;
    this._m1Rate.update(n);
    this._m5Rate.update(n);
    this._m15Rate.update(n);
  }

  start() {}

  end() {
    clearInterval(this._interval);
    this._interval = null;
  }

  /**
   * Refs the backing timer again. Idempotent.
   */
  ref() {
    if (this._interval && this._interval.ref) {
      this._interval.ref();
    }
  }

  /**
   * Unrefs the backing timer. The meter will not keep the event loop alive. Idempotent.
   */
  unref() {
    if (this._interval && this._interval.unref) {
      this._interval.unref();
    }
  }

  _tick() {
    this._m1Rate.tick();
    this._m5Rate.tick();
    this._m15Rate.tick();
  }

  /**
   * Resets all values. Meters initialized with custom options will be reset to the default settings (patch welcome).
   */
  reset() {
    this.end();
    this._initializeState();
  }

  meanRate() {
    if (this._count === 0) {
      return 0;
    }

    const elapsed = this._getTime() - this._startTime;
    return this._count / elapsed * this._rateUnit;
  }

  currentRate() {
    const currentSum = this._currentSum;
    const duration = this._getTime() - this._lastToJSON;
    const currentRate = currentSum / duration * this._rateUnit;

    this._currentSum = 0;
    this._lastToJSON = this._getTime();

    // currentRate could be NaN if duration was 0, so fix that
    return currentRate || 0;
  }

  /**
   * @return {MeterData}
   */
  toJSON() {
    return {
      mean: this.meanRate(),
      count: this._count,
      currentRate: this.currentRate(),
      '1MinuteRate': this._m1Rate.rate(this._rateUnit),
      '5MinuteRate': this._m5Rate.rate(this._rateUnit),
      '15MinuteRate': this._m15Rate.rate(this._rateUnit)
    };
  }

  _getTime() {
    if (!process.hrtime) {
      return new Date().getTime();
    }

    const hrtime = process.hrtime();
    return hrtime[0] * 1000 + hrtime[1] / (1000 * 1000);
  }

  /**
   * The type of the Metric Impl. {@link MetricTypes}.
   * @return {string} The type of the Metric Impl.
   */
  getType() {
    return MetricTypes.METER;
  }
}

module.exports = Meter;

/**
 *
 * @interface MeterProperties
 * @typedef MeterProperties
 * @type {Object}
 * @property {number} rateUnit The rate unit. Defaults to 1000 (1 sec).
 * @property {number} tickInterval The interval in which the averages are updated. Defaults to 5000 (5 sec).
 * @property {boolean} keepAlive Optional flag to unref the associated timer. Defaults to `false`.
 * @example
 * const meter = new Meter({ rateUnit: 1000, tickInterval: 5000})
 */

/**
 * The data returned from Meter::toJSON()
 * @interface MeterData
 * @typedef MeterData
 * @typedef {object}
 * @property {number} mean The average rate since the meter was started.
 * @property {number} count The total of all values added to the meter.
 * @property {number} currentRate The rate of the meter since the last toJSON() call.
 * @property {number} 1MinuteRate The rate of the meter biased towards the last 1 minute.
 * @property {number} 5MinuteRate The rate of the meter biased towards the last 5 minutes.
 * @property {number} 15MinuteRate The rate of the meter biased towards the last 15 minutes.
 */


================================================
FILE: packages/measured-core/lib/metrics/Metric.js
================================================
/**
 * Interface for Metric types.
 *
 * Implementations
 * <p>
 * <li><a href="Counter.html">Counter</a>, things that increment or decrement.</li>
 * <li><a href="Gauge.html">Gauge</a>, values that can be read instantly via a supplied call back.</li>
 * <li><a href="Histogram.html">Histogram</a>, keeps a reservoir of statistically relevant values to explore their distribution.</li>
 * <li><a href="Meter.html">Meter</a>, things that are measured as events / interval.</li>
 * <li><a href="NoOpMeter.html">NoOpMeter</a>, an empty impl of meter, useful for supplying to a Timer, when you only care about the Histogram.</li>
 * <li><a href="SettableGauge.html">SettableGauge</a>, just like a Gauge but its value is set directly rather than supplied by a callback.</li>
 * <li><a href="CachedGauge.html">CachedGauge</a>, A Cached Gauge takes a function that returns a promise that resolves a value that should be cached and updated on a given interval.</li>
 * <li><a href="Timer.html">Timer</a>, timers are a combination of Meters and Histograms. They measure the rate as well as distribution of scalar events.</li>
 * </p>
 *
 * @interface Metric
 */
// eslint-disable-next-line no-unused-vars
class Metric {
  /**
   * Please note that dispite its name, this method can return raw numbers on
   * certain implementations such as counters and gauges.
   *
   * @return {any} Returns the data from the Metric
   */
  toJSON() {}

  /**
   * The type of the Metric Impl. {@link MetricTypes}.
   * @return {string} The type of the Metric Impl.
   */
  getType() {}
}

/**
 * An enum like object that is the set of core metric types that all implementors of {@link Metric} are.
 *
 * @typedef MetricTypes
 * @interface MetricTypes
 * @type {Object.<string, string>}
 * @property {COUNTER} The type for Counters.
 * @property {GAUGE} The type for Gauges.
 * @property {HISTOGRAM} The type for Histograms.
 * @property {METER} The type for Meters.
 * @property {TIMER} The type for Timers.
 */
const MetricTypes = {
  COUNTER: 'Counter',
  GAUGE: 'Gauge',
  HISTOGRAM: 'Histogram',
  METER: 'Meter',
  TIMER: 'Timer'
};

module.exports = {
  MetricTypes
};


================================================
FILE: packages/measured-core/lib/metrics/NoOpMeter.js
================================================
const { MetricTypes } = require('./Metric');

/**
 * A No-Op Impl of Meter that can be used with a timer, to only create histogram data.
 * This is useful for some time series aggregators that can calculate rates for you just off of sent count.
 *
 * @implements {Metric}
 * @example
 * const { NoOpMeter, Timer } = require('measured')
 * const meter = new NoOpMeter();
 * const timer = new Timer({meter: meter});
 * ...
 * // do some stuff with the timer and stopwatch api
 * ...
 */
// eslint-disable-next-line padded-blocks
class NoOpMeter {
  /**
   * No-Op impl
   * @param {number} n Number of events to mark.
   */
  // eslint-disable-next-line no-unused-vars
  mark(n) {}

  /**
   * No-Op impl
   */
  start() {}

  /**
   * No-Op impl
   */
  end() {}

  /**
   * No-Op impl
   */
  ref() {}

  /**
   * No-Op impl
   */
  unref() {}

  /**
   * No-Op impl
   */
  reset() {}

  /**
   * No-Op impl
   */
  meanRate() {}

  /**
   * No-Op impl
   */
  currentRate() {}

  /**
   * Returns an empty object
   * @return {{}}
   */
  toJSON() {
    return {};
  }

  /**
   * The type of the Metric Impl. {@link MetricTypes}.
   * @return {string} The type of the Metric Impl.
   */
  getType() {
    return MetricTypes.METER;
  }
}

module.exports = NoOpMeter;


================================================
FILE: packages/measured-core/lib/metrics/SettableGauge.js
================================================
const { MetricTypes } = require('./Metric');

/**
 * Works like a {@link Gauge}, but rather than getting its value from a callback, the value
 * is set when needed. This can be useful for setting a gauges value for asynchronous operations.
 * @implements {Metric}
 * @example
 * const settableGauge = new SettableGauge();
 * // Update the settable gauge ever 10'ish seconds
 * setInterval(() => {
 *     calculateSomethingAsync().then((value) => {
 *         settableGauge.setValue(value);
 *     });
 * }, 10000);
 */
class SettableGauge {
  /**
   * @param {SettableGaugeProperties} [options] See {@link SettableGaugeProperties}.
   */
  constructor(options) {
    options = options || {};
    this._value = options.initialValue || 0;
  }

  setValue(value) {
    this._value = value;
  }

  /**
   * @return {number} Settable Gauges directly return there current value.
   */
  toJSON() {
    return this._value;
  }

  /**
   * The type of the Metric Impl. {@link MetricTypes}.
   * @return {string} The type of the Metric Impl.
   */
  getType() {
    return MetricTypes.GAUGE;
  }
}

module.exports = SettableGauge;

/**
 * Properties that can be supplied to the constructor of a {@link Counter}
 *
 * @interface SettableGaugeProperties
 * @typedef SettableGaugeProperties
 * @type {Object}
 * @property {number} initialValue An initial value to use for this settable gauge. Defaults to 0.
 * @example
 * // Creates a Gauge that with an initial value of 500.
 * const settableGauge = new SettableGauge({ initialValue: 500 })
 *
 */


================================================
FILE: packages/measured-core/lib/metrics/Timer.js
================================================
const { MetricTypes } = require('./Metric');
const Histogram = require('./Histogram');
const Meter = require('./Meter');
const Stopwatch = require('../util/Stopwatch');

/**
 *
 * Timers are a combination of Meters and Histograms. They measure the rate as well as distribution of scalar events.
 * <p>
 * Since they are frequently used for tracking how long certain things take, they expose an API for that: See example 1.
 * <p>
 * But you can also use them as generic histograms that also track the rate of events: See example 2.
 *
 * @example
 * var Measured = require('measured')
 * var timer = new Measured.Timer();
 * http.createServer(function(req, res) {
 *     var stopwatch = timer.start();
 *     req.on('end', function() {
 *         stopwatch.end();
 *     });
 * });
 *
 *
 * @example
 * var Measured = require('measured')
 * var timer = new Measured.Timer();
 * http.createServer(function(req, res) {
 *    if (req.headers['content-length']) {
 *        timer.update(parseInt(req.headers['content-length'], 10));
 *    }
 * });
 *
 * @implements {Metric}
 */
class Timer {
  /**
   * @param {TimerProperties} [properties] See {@link TimerProperties}.
   */
  constructor(properties) {
    properties = properties || {};

    this._meter = properties.meter || new Meter({});
    this._histogram = properties.histogram || new Histogram({});
    this._getTime = properties.getTime;
    this._keepAlive = !!properties.keepAlive;

    if (!properties.keepAlive) {
      this.unref();
    }
  }

  /**
   * @return {Stopwatch} Returns a Stopwatch that has been started.
   */
  start() {
    const self = this;
    const watch = new Stopwatch({ getTime: this._getTime });

    watch.once('end', elapsed => {
      self.update(elapsed);
    });

    return watch;
  }

  /**
   * Updates the internal histogram with value and marks one event on the internal meter.
   * @param {number} value
   */
  update(value) {
    this._meter.mark();
    this._histogram.update(value);
  }

  /**
   * Resets all values. Timers initialized with custom options will be reset to the default settings.
   */
  reset() {
    this._meter.reset();
    this._histogram.reset();
  }

  end() {
    this._meter.end();
  }

  /**
   * Refs the backing timer again. Idempotent.
   */
  ref() {
    this._meter.ref();
  }

  /**
   * Unrefs the backing timer. The meter will not keep the event loop alive. Idempotent.
   */
  unref() {
    this._meter.unref();
  }

  /**
   * toJSON output:
   *
   * <li> meter: See <a href="#meter">Meter</a>#toJSON output docs above.</li>
   * <li> histogram: See <a href="#histogram">Histogram</a>#toJSON output docs above.</a></li>
   *
   * @return {any}
   */
  toJSON() {
    return {
      meter: this._meter.toJSON(),
      histogram: this._histogram.toJSON()
    };
  }

  /**
   * The type of the Metric Impl. {@link MetricTypes}.
   * @return {string} The type of the Metric Impl.
   */
  getType() {
    return MetricTypes.TIMER;
  }
}

module.exports = Timer;

/**
 * @interface TimerProperties
 * @typedef TimerProperties
 * @type {Object}
 * @property {Meter} meter The internal meter to use. Defaults to a new {@link Meter}.
 * @property {Histogram} histogram The internal histogram to use. Defaults to a new {@link Histogram}.
 * @property {function} getTime optional function override for supplying time to the {@link Stopwatch}
 * @property {boolean} keepAlive Optional flag to unref the associated timer. Defaults to `false`.
 */


================================================
FILE: packages/measured-core/lib/util/BinaryHeap.js
================================================
/**
 * Based on http://en.wikipedia.org/wiki/Binary_Heap
 * as well as http://eloquentjavascript.net/appendix2.html
 */
class BinaryHeap {
  constructor(options) {
    options = options || {};

    this._elements = options.elements || [];
    this._score = options.score || this._score;
  }

  /**
   * Add elements to the binary heap.
   * @param {any[]} elements
   */
  add(...elements) {
    elements.forEach(element => {
      this._elements.push(element);
      this._bubble(this._elements.length - 1);
    });
  }

  first() {
    return this._elements[0];
  }

  removeFirst() {
    const root = this._elements[0];
    const last = this._elements.pop();

    if (this._elements.length > 0) {
      this._elements[0] = last;
      this._sink(0);
    }

    return root;
  }

  clone() {
    return new BinaryHeap({
      elements: this.toArray(),
      score: this._score
    });
  }

  toSortedArray() {
    const array = [];
    const clone = this.clone();
    let element;

    while (true) {
      element = clone.removeFirst();
      if (element === undefined) {
        break;
      }

      array.push(element);
    }

    return array;
  }

  toArray() {
    return [].concat(this._elements);
  }

  size() {
    return this._elements.length;
  }

  _bubble(bubbleIndex) {
    const bubbleElement = this._elements[bubbleIndex];
    const bubbleScore = this._score(bubbleElement);
    let parentIndex;
    let parentElement;
    let parentScore;

    while (bubbleIndex > 0) {
      parentIndex = this._parentIndex(bubbleIndex);
      parentElement = this._elements[parentIndex];
      parentScore = this._score(parentElement);

      if (bubbleScore <= parentScore) {
        break;
      }

      this._elements[parentIndex] = bubbleElement;
      this._elements[bubbleIndex] = parentElement;
      bubbleIndex = parentIndex;
    }
  }

  _sink(sinkIndex) {
    const sinkElement = this._elements[sinkIndex];
    const sinkScore = this._score(sinkElement);
    const { length } = this._elements;
    let swapIndex;
    let swapScore;
    let swapElement;
    let childIndexes;
    let i;
    let childIndex;
    let childElement;
    let childScore;

    while (true) {
      swapIndex = null;
      swapScore = null;
      swapElement = null;
      childIndexes = this._childIndexes(sinkIndex);

      for (i = 0; i < childIndexes.length; i++) {
        childIndex = childIndexes[i];

        if (childIndex >= length) {
          break;
        }

        childElement = this._elements[childIndex];
        childScore = this._score(childElement);

        if (childScore > sinkScore) {
          if (swapScore === null || swapScore < childScore) {
            swapIndex = childIndex;
            swapScore = childScore;
            swapElement = childElement;
          }
        }
      }

      if (swapIndex === null) {
        break;
      }

      this._elements[swapIndex] = sinkElement;
      this._elements[sinkIndex] = swapElement;
      sinkIndex = swapIndex;
    }
  }

  _parentIndex(index) {
    return Math.floor((index - 1) / 2);
  }

  _childIndexes(index) {
    return [2 * index + 1, 2 * index + 2];
  }

  _score(element) {
    return element.valueOf();
  }
}

module.exports = BinaryHeap;


================================================
FILE: packages/measured-core/lib/util/ExponentiallyDecayingSample.js
================================================
const BinaryHeap = require('./BinaryHeap');
const units = require('./units');

const RESCALE_INTERVAL = units.HOURS;
const ALPHA = 0.015;
const SIZE = 1028;

/**
 * ExponentiallyDecayingSample
 */
class ExponentiallyDecayingSample {
  constructor(options) {
    options = options || {};

    this._elements = new BinaryHeap({
      score: element => -element.priority
    });

    this._rescaleInterval = options.rescaleInterval || RESCALE_INTERVAL;
    this._alpha = options.alpha || ALPHA;
    this._size = options.size || SIZE;
    this._random = options.random || this._random;
    this._landmark = null;
    this._nextRescale = null;
  }

  update(value, timestamp) {
    const now = Date.now();
    if (!this._landmark) {
      this._landmark = now;
      this._nextRescale = this._landmark + this._rescaleInterval;
    }

    timestamp = timestamp || now;

    const newSize = this._elements.size() + 1;

    const element = {
      priority: this._priority(timestamp - this._landmark),
      value: value
    };

    if (newSize <= this._size) {
      this._elements.add(element);
    } else if (element.priority > this._elements.first().priority) {
      this._elements.removeFirst();
      this._elements.add(element);
    }

    if (now >= this._nextRescale) {
      this._rescale(now);
    }
  }

  toSortedArray() {
    return this._elements.toSortedArray().map(element => element.value);
  }

  toArray() {
    return this._elements.toArray().map(element => element.value);
  }

  toArrayWithWeights() {
    return this._elements.toArray();
  }

  _weight(age) {
    // We divide by 1000 to not run into huge numbers before reaching a
    // rescale event.
    return Math.exp(this._alpha * (age / 1000));
  }

  _priority(age) {
    return this._weight(age) / this._random();
  }

  _random() {
    return Math.random();
  }

  _rescale(now) {
    now = now || Date.now();

    const self = this;
    const oldLandmark = this._landmark;
    this._landmark = now || Date.now();
    this._nextRescale = now + this._rescaleInterval;

    const factor = self._priority(-(self._landmark - oldLandmark));

    this._elements.toArray().forEach(element => {
      element.priority *= factor;
    });
  }
}

module.exports = ExponentiallyDecayingSample;


================================================
FILE: packages/measured-core/lib/util/ExponentiallyMovingWeightedAverage.js
================================================
const units = require('./units');

const TICK_INTERVAL = 5 * units.SECONDS;

/**
 * ExponentiallyMovingWeightedAverage
 */
class ExponentiallyMovingWeightedAverage {
  constructor(timePeriod, tickInterval) {
    this._timePeriod = timePeriod || units.MINUTE;
    this._tickInterval = tickInterval || TICK_INTERVAL;
    this._alpha = 1 - Math.exp(-this._tickInterval / this._timePeriod);
    this._count = 0;
    this._rate = 0;
  }

  update(n) {
    this._count += n;
  }

  tick() {
    const instantRate = this._count / this._tickInterval;
    this._count = 0;

    this._rate += this._alpha * (instantRate - this._rate);
  }

  rate(timeUnit) {
    return (this._rate || 0) * timeUnit;
  }
}

module.exports = ExponentiallyMovingWeightedAverage;


================================================
FILE: packages/measured-core/lib/util/Stopwatch.js
================================================
const { EventEmitter } = require('events');

/**
 * A simple object for tracking elapsed time
 *
 * @extends {EventEmitter}
 */
class Stopwatch extends EventEmitter {
  /**
   * Creates a started Stopwatch
   * @param {StopwatchProperties} [options] See {@link StopwatchProperties}
   */
  constructor(options) {
    super();
    options = options || {};
    EventEmitter.call(this);

    if (options.getTime) {
      this._getTime = options.getTime;
    }
    this._start = this._getTime();
    this._ended = false;
  }

  /**
   * Called to mark the end of the timer task
   * @return {number} the total execution time
   */
  end() {
    if (this._ended) {
      return null;
    }

    this._ended = true;
    const elapsed = this._getTime() - this._start;

    this.emit('end', elapsed);
    return elapsed;
  }

  _getTime() {
    if (!process.hrtime) {
      return Date.now();
    }

    const hrtime = process.hrtime();
    return hrtime[0] * 1000 + hrtime[1] / (1000 * 1000);
  }
}

module.exports = Stopwatch;

/**
 * @interface StopwatchProperties
 * @typedef StopwatchProperties
 * @type {Object}
 * @property {function} getTime optional function override for supplying time., defaults to new Date() / process.hrt()
 */


================================================
FILE: packages/measured-core/lib/util/units.js
================================================
const NANOSECONDS = 1 / (1000 * 1000);
const MICROSECONDS = 1 / 1000;
const MILLISECONDS = 1;
const SECONDS = 1000 * MILLISECONDS;
const MINUTES = 60 * SECONDS;
const HOURS = 60 * MINUTES;
const DAYS = 24 * HOURS;

/**
 * Time units, as found in Java: {@link http://download.oracle.com/javase/6/docs/api/java/util/concurrent/TimeUnit.html}
 * @module timeUnits
 * @example
 * const timeUnit = require('measured-core').unit
 * setTimeout(() => {}, 5 * timeUnit.MINUTES)
 */
module.exports = {
  /**
   * nanoseconds in milliseconds
   * @type {number}
   */
  NANOSECONDS,
  /**
   * microseconds in milliseconds
   * @type {number}
   */
  MICROSECONDS,
  /**
   * milliseconds in milliseconds
   * @type {number}
   */
  MILLISECONDS,
  /**
   * seconds in milliseconds
   * @type {number}
   */
  SECONDS,
  /**
   * minutes in milliseconds
   * @type {number}
   */
  MINUTES,
  /**
   * hours in milliseconds
   * @type {number}
   */
  HOURS,
  /**
   * days in milliseconds
   * @type {number}
   */
  DAYS
};


================================================
FILE: packages/measured-core/lib/validators/metricValidators.js
================================================
const { MetricTypes } = require('../metrics/Metric');

// TODO: Object.values(...) does not exist in Node.js 6.x, switch after LTS period ends.
// const metricTypeValues = Object.values(MetricTypes);
const metricTypeValues = Object.keys(MetricTypes).map(key => MetricTypes[key]);

/**
 * This module contains various validators to validate publicly exposed input.
 *
 * @module metricValidators
 */
module.exports = {
  /**
   * Validates that a metric implements the metric interface.
   *
   * @param {Metric} metric The object that is supposed to be a metric.
   */
  validateMetric: metric => {
    if (!metric) {
      throw new TypeError('The metric was undefined, when it was required');
    }
    if (typeof metric.toJSON !== 'function') {
      throw new TypeError('Metrics must implement toJSON(), see the Metric interface in the docs.');
    }
    if (typeof metric.getType !== 'function') {
      throw new TypeError('Metrics must implement getType(), see the Metric interface in the docs.');
    }
    const type = metric.getType();

    if (!metricTypeValues.includes(type)) {
      throw new TypeError(
        `Metric#getType(), must return a type defined in MetricsTypes. Found: ${type}, Valid values: ${metricTypeValues.join(
          ', '
        )}`
      );
    }
  }
};


================================================
FILE: packages/measured-core/package.json
================================================
{
  "name": "measured-core",
  "description": "A Node library for measuring and reporting application-level metrics.",
  "version": "2.0.0",
  "homepage": "https://yaorg.github.io/node-measured/",
  "engines": {
    "node": ">= 5.12"
  },
  "publishConfig": {
    "access": "public"
  },
  "main": "./lib/index.js",
  "scripts": {
    "clean": "rm -fr build",
    "format": "prettier --write './lib/**/*.{ts,js}'",
    "lint": "eslint lib --ext .js",
    "test:node": "mocha './test/**/test-*.js'",
    "test:node:coverage": "nyc --report-dir build/coverage/ --reporter=html --reporter=text mocha './test/**/test-*.js'",
    "test:browser": "mochify './test/**/test-*.js'",
    "test": "yarn test:node:coverage && yarn test:browser",
    "coverage": "nyc report --reporter=text-lcov | coveralls"
  },
  "dependencies": {
    "binary-search": "^1.3.3",
    "optional-js": "^2.0.0"
  },
  "repository": {
    "url": "git://github.com/yaorg/node-measured.git"
  },
  "files": [
    "lib",
    "README.md"
  ],
  "license": "MIT",
  "devDependencies": {
    "jsdoc": "^3.5.5"
  }
}


================================================
FILE: packages/measured-core/test/common.js
================================================
'use strict';

/*
var common = exports;
var path   = require('path');

common.dir      = {};
common.dir.root = path.dirname(__dirname);
common.dir.lib  = path.join(common.dir.root, 'lib');

common.measured = require(common.dir.root);
*/
exports.measured = require('../lib/index');


================================================
FILE: packages/measured-core/test/integration/test-Collection_end.js
================================================
'use strict';

var common = require('../common');

var collection = new common.measured.Collection();

collection.timer('a').start();
collection.meter('b').start();
collection.counter('c');

collection.end();


================================================
FILE: packages/measured-core/test/unit/metrics/test-CachedGauge.js
================================================
/*global describe, it, beforeEach, afterEach*/
const TimeUnits = require('../../../lib/util/units');
const CachedGauge = require('../../../lib/metrics/CachedGauge');
const assert = require('assert');

describe('CachedGauge', () => {
  let cachedGauge;
  it('A cachedGauge immediately calls the callback to set its initial value', () => {
    cachedGauge = new CachedGauge(
      () => {
        return new Promise(resolve => {
          resolve(10);
        });
      },
      1,
      TimeUnits.MINUTES
    ); // Shouldn't update in the unit test.

    return wait(5 * TimeUnits.MILLISECONDS).then(() => {
      assert.equal(cachedGauge.toJSON(), 10);
    });
  });

  it('A cachedGauge calls the callback at the interval provided', () => {
    const values = [1, 2];
    cachedGauge = new CachedGauge(
      () => {
        return new Promise(resolve => {
          resolve(values.shift());
        });
      },
      5,
      TimeUnits.MILLISECONDS
    );

    return wait(7 * TimeUnits.MILLISECONDS).then(() => {
      assert.equal(cachedGauge.toJSON(), 2);
      assert.equal(values.length, 0, 'the callback should have been called 2x, emptying the values array');
    });
  });

  afterEach(() => {
    if (cachedGauge) {
      cachedGauge.end();
    }
  });
});

const wait = waitInterval => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve();
    }, waitInterval);
  });
};


================================================
FILE: packages/measured-core/test/unit/metrics/test-Counter.js
================================================
/*global describe, it, beforeEach, afterEach*/
'use strict';

var common = require('../../common');
var assert = require('assert');
var Counter = common.measured.Counter;

describe('Counter', function() {
  var counter;
  beforeEach(function() {
    counter = new Counter();
  });

  it('has initial value of 0', function() {
    var json = counter.toJSON();
    assert.deepEqual(json, 0);
  });

  it('can be initialized with a given count', function() {
    counter = new Counter({ count: 5 });
    assert.equal(counter.toJSON(), 5);
  });

  it('#inc works incrementally', function() {
    counter.inc(5);
    assert.equal(counter.toJSON(), 5);

    counter.inc(3);
    assert.equal(counter.toJSON(), 8);
  });

  it('#inc defaults to 1', function() {
    counter.inc();
    assert.equal(counter.toJSON(), 1);

    counter.inc();
    assert.equal(counter.toJSON(), 2);
  });

  it('#inc adds zero', function() {
    counter.inc(0);
    assert.equal(counter.toJSON(), 0);
  });

  it('#dec works incrementally', function() {
    counter.dec(3);
    assert.equal(counter.toJSON(), -3);

    counter.dec(2);
    assert.equal(counter.toJSON(), -5);
  });

  it('#dec defaults to 1', function() {
    counter.dec();
    assert.equal(counter.toJSON(), -1);

    counter.dec();
    assert.equal(counter.toJSON(), -2);
  });

  it('#dec substracts zero', function() {
    counter.dec(0);
    assert.equal(counter.toJSON(), 0);
  });

  it('#reset works', function() {
    counter.inc(23);
    assert.equal(counter.toJSON(), 23);

    counter.reset();
    assert.equal(counter.toJSON(), 0);

    counter.reset(50);
    assert.equal(counter.toJSON(), 50);
  });

  it('returns the expected type', () => {
    assert.equal(counter.getType(), 'Counter');
  });
});


================================================
FILE: packages/measured-core/test/unit/metrics/test-Gauge.js
================================================
/*global describe, it, beforeEach, afterEach*/
'use strict';

var common = require('../../common');
var assert = require('assert');

describe('Gauge', function() {
  it('reads value from function', function() {
    var i = 0;

    var gauge = new common.measured.Gauge(function() {
      return i++;
    });

    assert.equal(gauge.toJSON(), 0);
    assert.equal(gauge.toJSON(), 1);
  });

  it('returns the expected type', () => {
    const gauge = new common.measured.SettableGauge();
    assert.equal(gauge.getType(), 'Gauge');
  });
});


================================================
FILE: packages/measured-core/test/unit/metrics/test-Histogram.js
================================================
/*global describe, it, beforeEach, afterEach*/
'use strict';

var common = require('../../common');
var assert = require('assert');
var sinon = require('sinon');
var Histogram = common.measured.Histogram;
var EDS = common.measured.ExponentiallyDecayingSample;

describe('Histogram', function() {
  var histogram;
  beforeEach(function() {
    histogram = new Histogram();
  });

  it('all values are null in the beginning', function() {
    var json = histogram.toJSON();
    assert.strictEqual(json.min, null);
    assert.strictEqual(json.max, null);
    assert.strictEqual(json.sum, 0);
    assert.strictEqual(json.variance, null);
    assert.strictEqual(json.mean, 0);
    assert.strictEqual(json.stddev, null);
    assert.strictEqual(json.count, 0);
    assert.strictEqual(json.median, null);
    assert.strictEqual(json.p75, null);
    assert.strictEqual(json.p95, null);
    assert.strictEqual(json.p99, null);
    assert.strictEqual(json.p999, null);
  });

  it('returns the expected type', () => {
    assert.equal(histogram.getType(), 'Histogram');
  });
});

describe('Histogram#update', function() {
  var sample;
  var histogram;
  beforeEach(function() {
    sample = sinon.stub(new EDS());
    histogram = new Histogram({ sample: sample });

    sample.toArray.returns([]);
  });

  it('updates underlaying sample', function() {
    histogram.update(5);
    assert.ok(sample.update.calledWith(5));
  });

  it('keeps track of min', function() {
    histogram.update(5);
    histogram.update(3);
    histogram.update(6);

    assert.equal(histogram.toJSON().min, 3);
  });

  it('keeps track of max', function() {
    histogram.update(5);
    histogram.update(9);
    histogram.update(3);

    assert.equal(histogram.toJSON().max, 9);
  });

  it('keeps track of sum', function() {
    histogram.update(5);
    histogram.update(1);
    histogram.update(12);

    assert.equal(histogram.toJSON().sum, 18);
  });

  it('keeps track of count', function() {
    histogram.update(5);
    histogram.update(1);
    histogram.update(12);

    assert.equal(histogram.toJSON().count, 3);
  });

  it('keeps track of mean', function() {
    histogram.update(5);
    histogram.update(1);
    histogram.update(12);

    assert.equal(histogram.toJSON().mean, 6);
  });

  it('keeps track of variance (example without variance)', function() {
    histogram.update(5);
    histogram.update(5);
    histogram.update(5);

    assert.equal(histogram.toJSON().variance, 0);
  });

  it('keeps track of variance (example with variance)', function() {
    histogram.update(1);
    histogram.update(2);
    histogram.update(3);
    histogram.update(4);

    assert.equal(histogram.toJSON().variance.toFixed(3), '1.667');
  });

  it('keeps track of stddev', function() {
    histogram.update(1);
    histogram.update(2);
    histogram.update(3);
    histogram.update(4);

    assert.equal(histogram.toJSON().stddev.toFixed(3), '1.291');
  });

  it('keeps track of percentiles', function() {
    var values = [];
    var i;
    for (i = 1; i <= 100; i++) {
      values.push(i);
    }
    sample.toArray.returns(values);

    var json = histogram.toJSON();
    assert.equal(json.median.toFixed(3), '50.500');
    assert.equal(json.p75.toFixed(3), '75.750');
    assert.equal(json.p95.toFixed(3), '95.950');
    assert.equal(json.p99.toFixed(3), '99.990');
    assert.equal(json.p999.toFixed(3), '100.000');
  });
});

describe('Histogram#percentiles', function() {
  var sample;
  var histogram;
  beforeEach(function() {
    sample = sinon.stub(new EDS());
    histogram = new Histogram({ sample: sample });

    var values = [];
    var i;
    for (i = 1; i <= 100; i++) {
      values.push(i);
    }

    var swapWith;
    var value;
    for (i = 0; i < 100; i++) {
      swapWith = Math.floor(Math.random() * 100);
      value = values[i];

      values[i] = values[swapWith];
      values[swapWith] = value;
    }

    sample.toArray.returns(values);
  });

  it('calculates single percentile correctly', function() {
    var percentiles = histogram._percentiles([0.5]);
    assert.equal(percentiles[0.5], 50.5);

    percentiles = histogram._percentiles([0.99]);
    assert.equal(percentiles[0.99], 99.99);
  });
});

describe('Histogram#weightedPercentiles', function() {
  var sample;
  var histogram;
  beforeEach(function() {
    sample = sinon.stub(new EDS());
    histogram = new Histogram({
      sample: sample,
      percentilesMethod: Histogram.weightedPercentiles
    });

    var values = [];
    var i;
    for (i = 1; i <= 100; i++) {
      values.push({ value: i, priority: 1 });
    }

    var swapWith;
    var value;
    for (i = 0; i < 100; i++) {
      swapWith = Math.floor(Math.random() * 100);
      value = values[i];

      values[i] = values[swapWith];
      values[swapWith] = value;
    }

    sample.toArrayWithWeights.returns(values);
    sample.toArray.returns(
      values.map(function(item) {
        return item.value;
      })
    );
  });

  it('calculates single percentile correctly', function() {
    var percentiles = histogram._percentiles([0.5]);
    assert.equal(percentiles[0.5], 50.5);

    percentiles = histogram._percentiles([0.99]);
    assert.equal(percentiles[0.99], 99.99);
  });
});

describe('Histogram#reset', function() {
  var sample;
  var histogram;
  beforeEach(function() {
    sample = new EDS();
    histogram = new Histogram({ sample: sample });
  });

  it('resets all values', function() {
    histogram.update(5);
    histogram.update(2);
    var json = histogram.toJSON();

    var key;
    for (key in json) {
      if (json.hasOwnProperty(key)) {
        assert.ok(typeof json[key] === 'number');
      }
    }

    histogram.reset();
    json = histogram.toJSON();

    for (key in json) {
      if (json.hasOwnProperty(key)) {
        assert.ok(json[key] === 0 || json[key] === null);
      }
    }
  });
});

describe('Histogram#hasValues', function() {
  var histogram;
  beforeEach(function() {
    histogram = new Histogram();
  });

  it('has values', function() {
    histogram.update(5);
    assert.ok(histogram.hasValues());
  });

  it('has no values', function() {
    assert.equal(histogram.hasValues(), false);
  });
});


================================================
FILE: packages/measured-core/test/unit/metrics/test-Meter.js
================================================
/*global describe, it, beforeEach, afterEach*/
'use strict';

var common = require('../../common');
var assert = require('assert');
var sinon = require('sinon');
var units = common.measured.units;

describe('Meter', function() {
  var meter;
  var clock;
  beforeEach(function() {
    clock = sinon.useFakeTimers();
    meter = new common.measured.Meter({
      getTime: function() {
        return new Date().getTime();
      }
    });
  });

  afterEach(function() {
    clock.restore();
  });

  it('all values are correctly initialized', function() {
    assert.deepEqual(meter.toJSON(), {
      mean: 0,
      count: 0,
      currentRate: 0,
      '1MinuteRate': 0,
      '5MinuteRate': 0,
      '15MinuteRate': 0
    });
  });

  it('supports rates override from opts', function() {
    var rate = sinon.stub().returns(666);
    var properties = {
      m1Rate: { rate: rate },
      m5Rate: { rate: rate },
      m15Rate: { rate: rate }
    };
    var json = new common.measured.Meter(properties).toJSON();

    assert.equal(json['1MinuteRate'].toFixed(0), '666');
    assert.equal(json['5MinuteRate'].toFixed(0), '666');
    assert.equal(json['15MinuteRate'].toFixed(0), '666');
  });

  it('decay over two marks and ticks', function() {
    meter.mark(5);
    meter._tick();

    var json = meter.toJSON();
    assert.equal(json.count, 5);
    assert.equal(json['1MinuteRate'].toFixed(4), '0.0800');
    assert.equal(json['5MinuteRate'].toFixed(4), '0.0165');
    assert.equal(json['15MinuteRate'].toFixed(4), '0.0055');

    meter.mark(10);
    meter._tick();

    json = meter.toJSON();
    assert.equal(json.count, 15);
    assert.equal(json['1MinuteRate'].toFixed(3), '0.233');
    assert.equal(json['5MinuteRate'].toFixed(3), '0.049');
    assert.equal(json['15MinuteRate'].toFixed(3), '0.017');
  });

  it('mean rate', function() {
    meter.mark(5);
    clock.tick(5000);

    var json = meter.toJSON();
    assert.equal(json.mean, 1);

    clock.tick(5000);

    json = meter.toJSON();
    assert.equal(json.mean, 0.5);
  });

  it('currentRate is the observed rate since the last toJSON call', function() {
    meter.mark(1);
    meter.mark(2);
    meter.mark(3);

    clock.tick(3000);

    assert.equal(meter.toJSON().currentRate, 2);
  });

  it('currentRate resets by reading it', function() {
    meter.mark(1);
    meter.mark(2);
    meter.mark(3);

    meter.toJSON();
    assert.strictEqual(meter.toJSON().currentRate, 0);
  });

  it('currentRate also resets internal duration timer by reading it', function() {
    meter.mark(1);
    meter.mark(2);
    meter.mark(3);
    clock.tick(1000);
    meter.toJSON();

    clock.tick(1000);
    meter.toJSON();

    meter.mark(1);
    clock.tick(1000);
    assert.strictEqual(meter.toJSON().currentRate, 1);
  });

  it('#reset resets all values', function() {
    meter.mark(1);
    var json = meter.toJSON();

    var key, value;
    for (key in json) {
      if (json.hasOwnProperty(key)) {
        value = json[key];
        assert.ok(typeof value === 'number');
      }
    }

    meter.reset();
    json = meter.toJSON();

    for (key in json) {
      if (json.hasOwnProperty(key)) {
        value = json[key];
        assert.ok(value === 0 || value === null);
      }
    }
  });

  it('returns the expected type', () => {
    assert.equal(meter.getType(), 'Meter');
  });
});


================================================
FILE: packages/measured-core/test/unit/metrics/test-NoOpMeter.js
================================================
/*global describe, it, beforeEach, afterEach*/

var common = require('../../common');
var assert = require('assert');

describe('NoOpMeter', () => {
  let meter;

  beforeEach(() => {
    meter = new common.measured.NoOpMeter();
  });

  it('always returns empty object', () => {
    assert.deepEqual(meter.toJSON(), {});
  });

  it('returns the expected type', () => {
    assert.equal(meter.getType(), 'Meter');
  });
});


================================================
FILE: packages/measured-core/test/unit/metrics/test-SettableGauge.js
================================================
/*global describe, it, beforeEach, afterEach*/
'use strict';

var common = require('../../common');
var assert = require('assert');

describe('SettableGauge', function() {
  it('can be set with an initial value', () => {
    const gauge = new common.measured.SettableGauge({ initialValue: 5 });
    assert.equal(gauge.toJSON(), 5);
    gauge.setValue(11);
    assert.equal(gauge.toJSON(), 11);
  });

  it('reads value from internal state', () => {
    const gauge = new common.measured.SettableGauge();
    assert.equal(gauge.toJSON(), 0);
    gauge.setValue(5);
    assert.equal(gauge.toJSON(), 5);
  });

  it('returns the expected type', () => {
    const gauge = new common.measured.SettableGauge();
    assert.equal(gauge.getType(), 'Gauge');
  });
});


================================================
FILE: packages/measured-core/test/unit/metrics/test-Timer.js
================================================
/*global describe, it, beforeEach, afterEach*/
'use strict';

var common = require('../../common');
var assert = require('assert');
var sinon = require('sinon');
var Timer = common.measured.Timer;
var Histogram = common.measured.Histogram;
var Meter = common.measured.Meter;

describe('Timer', function() {
  var timer;
  var meter;
  var histogram;
  var clock;
  beforeEach(function() {
    clock = sinon.useFakeTimers();
    meter = sinon.stub(new Meter());
    histogram = sinon.stub(new Histogram());

    timer = new Timer({
      meter: meter,
      histogram: histogram,
      getTime: function() {
        return new Date().getTime();
      }
    });
  });

  afterEach(function() {
    clock.restore();
  });

  it('can be initialized without options', function() {
    timer = new Timer();
  });

  it('#update() marks the meter', function() {
    timer.update(5);

    assert.ok(meter.mark.calledOnce);
  });

  it('#update() updates the histogram', function() {
    timer.update(5);

    assert.ok(histogram.update.calledWith(5));
  });

  it('#toJSON() contains meter info', function() {
    meter.toJSON.returns({ a: 1, b: 2 });
    var json = timer.toJSON();

    assert.deepEqual(json.meter, { a: 1, b: 2 });
  });

  it('#toJSON() contains histogram info', function() {
    histogram.toJSON.returns({ c: 3, d: 4 });
    var json = timer.toJSON();

    assert.deepEqual(json.histogram, { c: 3, d: 4 });
  });

  it('#start returns a Stopwatch which updates the timer', function() {
    clock.tick(10);

    var watch = timer.start();
    clock.tick(50);
    watch.end();

    assert.ok(meter.mark.calledOnce);
    assert.equal(histogram.update.args[0][0], 50);
  });

  it('#reset is delegated to histogram and meter', function() {
    timer.reset();

    assert.ok(meter.reset.calledOnce);
    assert.ok(histogram.reset.calledOnce);
  });

  it('returns the expected type', () => {
    assert.equal(timer.getType(), 'Timer');
  });
});


================================================
FILE: packages/measured-core/test/unit/test-Collection.js
================================================
/*global describe, it, beforeEach, afterEach*/
'use strict';

var common = require('../common');
var assert = require('assert');

describe('Collection', function() {
  var collection;
  beforeEach(function() {
    collection = common.measured.createCollection();
  });

  it('with two counters', function() {
    collection = new common.measured.Collection('counters');
    var a = collection.counter('a');
    var b = collection.counter('b');

    a.inc(3);
    b.inc(5);

    assert.deepEqual(collection.toJSON(), {
      counters: {
        a: 3,
        b: 5
      }
    });
  });

  it('returns same metric object when given the same name', function() {
    var a1 = collection.counter('a');
    var a2 = collection.counter('a');

    assert.strictEqual(a1, a2);
  });

  it('throws exception when creating a metric without name', function() {
    assert.throws(function() {
      collection.counter();
    }, /You must supply a metric name/);
  });
});


================================================
FILE: packages/measured-core/test/unit/util/test-BinaryHeap.js
================================================
/*global describe, it, beforeEach, afterEach*/
'use strict';

var common = require('../../common');
var assert = require('assert');
var BinaryHeap = common.measured.BinaryHeap;

describe('BinaryHeap#toArray', function() {
  it('is empty in the beginning', function() {
    var heap = new BinaryHeap();
    assert.deepEqual(heap.toArray(), []);
  });

  it('does not leak internal references', function() {
    var heap = new BinaryHeap();
    var array = heap.toArray();
    array.push(1);

    assert.deepEqual(heap.toArray(), []);
  });
});

describe('BinaryHeap#toSortedArray', function() {
  it('is empty in the beginning', function() {
    var heap = new BinaryHeap();
    assert.deepEqual(heap.toSortedArray(), []);
  });

  it('does not leak internal references', function() {
    var heap = new BinaryHeap();
    var array = heap.toSortedArray();
    array.push(1);

    assert.deepEqual(heap.toSortedArray(), []);
  });

  it('returns a sorted array', function() {
    var heap = new BinaryHeap();
    heap.add(1, 2, 3, 4, 5, 6, 7, 8);

    assert.deepEqual(heap.toSortedArray(), [8, 7, 6, 5, 4, 3, 2, 1]);
  });
});

describe('BinaryHeap#add', function() {
  var heap;
  beforeEach(function() {
    heap = new BinaryHeap();
  });

  it('lets you add one element', function() {
    heap.add(1);

    assert.deepEqual(heap.toArray(), [1]);
  });

  it('lets you add two elements', function() {
    heap.add(1);
    heap.add(2);

    assert.deepEqual(heap.toArray(), [2, 1]);
  });

  it('lets you add two elements at once', function() {
    heap.add(1, 2);

    assert.deepEqual(heap.toArray(), [2, 1]);
  });

  it('places elements according to their valueOf()', function() {
    heap.add(2);
    heap.add(1);
    heap.add(3);

    assert.deepEqual(heap.toArray(), [3, 1, 2]);
  });
});

describe('BinaryHeap#removeFirst', function() {
  var heap;
  beforeEach(function() {
    heap = new BinaryHeap();
    heap.add(1, 2, 3, 4, 5, 6, 7, 8);
  });

  it('removeFirst returns the last element', function() {
    var element = heap.removeFirst();
    assert.equal(element, 8);
  });

  it('removeFirst removes the last element', function() {
    heap.removeFirst();
    assert.equal(heap.toArray().length, 7);
  });

  it('removeFirst works multiple times', function() {
    assert.equal(heap.removeFirst(), 8);
    assert.equal(heap.removeFirst(), 7);
    assert.equal(heap.removeFirst(), 6);
    assert.equal(heap.removeFirst(), 5);
    assert.equal(heap.removeFirst(), 4);
    assert.equal(heap.removeFirst(), 3);
    assert.equal(heap.removeFirst(), 2);
    assert.equal(heap.removeFirst(), 1);
    assert.equal(heap.removeFirst(), undefined);
  });
});

describe('BinaryHeap#first', function() {
  var heap;
  beforeEach(function() {
    heap = new BinaryHeap();
    heap.add(1, 2, 3);
  });

  it('returns the first element but does not remove it', function() {
    var element = heap.first();
    assert.equal(element, 3);

    assert.equal(heap.toArray().length, 3);
  });
});

describe('BinaryHeap#size', function() {
  it('takes custom score function', function() {
    var heap = new BinaryHeap({ elements: [1, 2, 3] });
    assert.equal(heap.size(), 3);
  });
});

describe('BinaryHeap', function() {
  it('takes custom score function', function() {
    var heap = new BinaryHeap({
      score: function(obj) {
        return -obj;
      }
    });

    heap.add(8, 7, 6, 5, 4, 3, 2, 1);
    assert.deepEqual(heap.toSortedArray(), [1, 2, 3, 4, 5, 6, 7, 8]);
  });
});


================================================
FILE: packages/measured-core/test/unit/util/test-ExponentiallyDecayingSample.js
================================================
/*global describe, it, beforeEach, afterEach*/
'use strict';

var common = require('../../common');
var assert = require('assert');
var EDS = common.measured.ExponentiallyDecayingSample;
var units = common.measured.units;

describe('ExponentiallyDecayingSample#toSortedArray', function() {
  var sample;
  beforeEach(function() {
    sample = new EDS({
      size: 3,
      random: function() {
        return 1;
      }
    });
  });

  it('returns an empty array by default', function() {
    assert.deepEqual(sample.toSortedArray(), []);
  });

  it('is always sorted by priority', function() {
    sample.update('a', Date.now() + 3000);
    sample.update('b', Date.now() + 2000);
    sample.update('c', Date.now());

    assert.deepEqual(sample.toSortedArray(), ['c', 'b', 'a']);
  });
});

describe('ExponentiallyDecayingSample#toArray', function() {
  var sample;
  beforeEach(function() {
    sample = new EDS({
      size: 3,
      random: function() {
        return 1;
      }
    });
  });

  it('returns an empty array by default', function() {
    assert.deepEqual(sample.toArray(), []);
  });

  it('may return an unsorted array', function() {
    sample.update('a', Date.now() + 3000);
    sample.update('b', Date.now() + 2000);
    sample.update('c', Date.now());

    assert.deepEqual(sample.toArray(), ['c', 'a', 'b']);
  });
});

describe('ExponentiallyDecayingSample#update', function() {
  var sample;
  beforeEach(function() {
    sample = new EDS({
      size: 2,
      random: function() {
        return 1;
      }
    });
  });

  it('can add one item', function() {
    sample.update('a');

    assert.deepEqual(sample.toSortedArray(), ['a']);
  });

  it('sorts items according to priority ascending', function() {
    sample.update('a', Date.now());
    sample.update('b', Date.now() + 1000);

    assert.deepEqual(sample.toSortedArray(), ['a', 'b']);
  });

  it('pops items with lowest priority', function() {
    sample.update('a', Date.now());
    sample.update('b', Date.now() + 1000);
    sample.update('c', Date.now() + 2000);

    assert.deepEqual(sample.toSortedArray(), ['b', 'c']);
  });

  it('items with too low of a priority do not make it in', function() {
    sample.update('a', Date.now() + 1000);
    sample.update('b', Date.now() + 2000);
    sample.update('c', Date.now());

    assert.deepEqual(sample.toSortedArray(), ['a', 'b']);
  });
});

describe('ExponentiallyDecayingSample#_rescale', function() {
  var sample;
  beforeEach(function() {
    sample = new EDS({
      size: 2,
      random: function() {
        return 1;
      }
    });
  });

  it('works as expected', function() {
    sample.update('a', Date.now() + 50 * units.MINUTES);
    sample.update('b', Date.now() + 55 * units.MINUTES);

    var elements = sample._elements.toSortedArray();
    assert.ok(elements[0].priority > 1000);
    assert.ok(elements[1].priority > 1000);

    sample._rescale(Date.now() + 60 * units.MINUTES);

    elements = sample._elements.toSortedArray();
    assert.ok(elements[0].priority < 1);
    assert.ok(elements[0].priority > 0);
    assert.ok(elements[1].priority < 1);
    assert.ok(elements[1].priority > 0);
  });
});


================================================
FILE: packages/measured-core/test/unit/util/test-ExponentiallyMovingWeightedAverage.js
================================================
/*global describe, it, beforeEach, afterEach*/
'use strict';

var common = require('../../common');
var assert = require('assert');
var units = common.measured.units;
var EMWA = common.measured.ExponentiallyMovingWeightedAverage;

describe('ExponentiallyMovingWeightedAverage', function() {
  it('decay over several updates and ticks', function() {
    var ewma = new EMWA(units.MINUTES, 5 * units.SECONDS);

    ewma.update(5);
    ewma.tick();

    assert.equal(ewma.rate(units.SECONDS).toFixed(3), '0.080');

    ewma.update(5);
    ewma.update(5);
    ewma.tick();

    assert.equal(ewma.rate(units.SECONDS).toFixed(3), '0.233');

    ewma.update(15);
    ewma.tick();

    assert.equal(ewma.rate(units.SECONDS).toFixed(3), '0.455');

    var i;
    for (i = 0; i < 200; i++) {
      ewma.update(15);
      ewma.tick();
    }

    assert.equal(ewma.rate(units.SECONDS).toFixed(3), '3.000');
  });
});


================================================
FILE: packages/measured-core/test/unit/util/test-Stopwatch.js
================================================
/*global describe, it, beforeEach, afterEach*/
'use strict';

var common = require('../../common');
var assert = require('assert');
var Stopwatch = common.measured.Stopwatch;
var sinon = require('sinon');

describe('Stopwatch', function() {
  var watch;
  var clock;
  beforeEach(function() {
    clock = sinon.useFakeTimers();
    watch = new Stopwatch({
      getTime: function() {
        return new Date().getTime();
      }
    });
  });

  afterEach(function() {
    clock.restore();
  });

  it('returns time on end', function() {
    clock.tick(100);

    var elapsed = watch.end();
    assert.equal(elapsed, 100);
  });

  it('emits time on end', function() {
    clock.tick(20);

    var time;
    watch.on('end', function(_time) {
      time = _time;
    });

    watch.end();

    assert.equal(time, 20);
  });

  it('becomes useless after being ended once', function() {
    clock.tick(20);

    var time;
    watch.on('end', function(_time) {
      time = _time;
    });

    assert.equal(watch.end(), 20);
    assert.equal(time, 20);

    time = null;
    assert.equal(watch.end(), undefined);
    assert.equal(time, null);
  });
});


================================================
FILE: packages/measured-node-metrics/README.md
================================================
# Measured Node Metrics

Various metrics generators and http framework middlewares that can be used with a self reporting metrics registry to easily instrument metrics for a node app.

[![npm](https://img.shields.io/npm/v/measured-node-metrics.svg)](https://www.npmjs.com/package/measured-node-metrics) 

## Install

```
npm install measured-node-metrics
```

## What is in this package

### [Measured Node Metrics Module](https://yaorg.github.io/node-measured/module-measured-node-metrics.html)
See the docs for the main module to see the exported helper functions and maps of metric generators for various system and os metrics.

## Example usage

```javascript
const express = require('express');
const { createProcessMetrics, createOSMetrics, createExpressMiddleware } = require('measured-node-metrics');

const registry = new SelfReportingMetricsRegistry(new SomeReporterImple());

// Create and register default OS metrics
createOSMetrics(registry);
// Create and register default process metrics
createProcessMetrics(registry);
// Use the express middleware
const app = express();
app.use(createExpressMiddleware(registry));

// Implement the rest of app
```

You can also create your own middleware if your not using express, (please contribute it)
```javascript
  const { onRequestStart, onRequestEnd } = require('measured-node-metrics');

  /**
   * Creates an Express middleware that reports a timer on request data.
   * With this middleware you will get requests counts and latency percentiles all filterable by status codes, http method, and uri paths.
   *
   * @param {SelfReportingMetricsRegistry} metricsRegistry
   * @param {number} [reportingIntervalInSeconds]
   * @return {Function}
   */
  createExpressMiddleware: (metricsRegistry, reportingIntervalInSeconds) => {
    return (req, res, next) => {
      const stopwatch = onRequestStart();

      req.on('end', () => {
        const { method } = req;
        const { statusCode } = res;
        // path variables should be stripped in order to avoid runaway time series creation, 
        // /v1/cars/:id should be one dimension rather than n, one for each id.
        const uri = req.route ? req.route.path : '_unknown';
        onRequestEnd(metricsRegistry, stopwatch, method, statusCode, uri, reportingIntervalInSeconds);
      });

      next();
    };
  }
```


================================================
FILE: packages/measured-node-metrics/lib/index.js
================================================
const { nodeProcessMetrics, createProcessMetrics } = require('./nodeProcessMetrics');
const { nodeOsMetrics, createOSMetrics } = require('./nodeOsMetrics');
const { createExpressMiddleware, createKoaMiddleware, onRequestStart, onRequestEnd } = require('./nodeHttpRequestMetrics');

/**
 * The main module for the measured-node-metrics lib.
 *
 * Various functions to help create node metrics and http framework middlewares
 * that can be used with a self reporting metrics registry to easily instrument metrics for a node app.
 *
 * @module measured-node-metrics
 */
module.exports = {
  /**
   * Map of metric names and a functions that can be used to generate that metric object that can be registered with a
   * self reporting metrics registry or used as seen fit.
   *
   * See {@link nodeProcessMetrics}.
   *
   * @type {Object.<string, function>}
   */
  nodeProcessMetrics,

  /**
   * Method that can be used to add a set of default node process metrics to your node app.
   *
   * registers all metrics defined in the {@link nodeProcessMetrics} map.
   *
   * @function
   * @name createProcessMetrics
   * @param {SelfReportingMetricsRegistry} metricsRegistry
   * @param {Dimensions} customDimensions
   * @param {number} reportingIntervalInSeconds
   */
  createProcessMetrics,

  /**
   * Map of metric names and a functions that can be used to generate that metric object that can be registered with a
   * self reporting metrics registry or used as seen fit.
   *
   * See {@link nodeOsMetrics}.
   *
   * @type {Object.<string, function>}
   */
  nodeOsMetrics,

  /**
   * Method that can be used to add a set of default node process metrics to your app.
   *
   * registers all metrics defined in the {@link nodeOsMetrics} map.
   *
   * @function
   * @name createOSMetrics
   * @param {SelfReportingMetricsRegistry} metricsRegistry
   * @param {Dimensions} customDimensions
   * @param {number} reportingIntervalInSeconds
   */
  createOSMetrics,

  /**
   * Creates an Express middleware that reports a timer on request data.
   * With this middleware you will get requests counts and latency percentiles all filterable by status codes, http method, and uri paths.
   *
   * @function
   * @name createExpressMiddleware
   * @param {SelfReportingMetricsRegistry} metricsRegistry
   * @param {number} [reportingIntervalInSeconds]
   * @return {Function}
   */
  createExpressMiddleware,

  /**
   * Creates a Koa middleware that reports a timer on request data.
   * With this middleware you will get requests counts and latency percentiles all filterable by status codes, http method, and uri paths.
   *
   * @function
   * @name createExpressMiddleware
   * @param {SelfReportingMetricsRegistry} metricsRegistry
   * @param {number} [reportingIntervalInSeconds]
   * @return {Function}
   */
  createKoaMiddleware,

  /**
   * At the start of the request, create a stopwatch, that starts tracking how long the request is taking.
   * @function
   * @name onRequestStart
   * @return {Stopwatch}
   */
  onRequestStart,

  /**
   * When the request ends stop the stop watch and create or update the timer for requests that tracked by method, statuscode, path.
   * The timers (meters and histograms) that get reported will be filterable by status codes, http method, the uri path.
   * You will be able to create dash boards such as success percentage, latency percentiles by path and method, etc.
   *
   * @function
   * @name onRequestEnd
   * @param metricsRegistry The Self Reporting Metrics Registry
   * @param stopwatch The stopwatch created by onRequestStart
   * @param method The Http Method for the request
   * @param statusCode The status code for the response
   * @param [uri] The uri for the request. Please note to avoid out of control time series dimension creation spread,
   * you would want to strip out ids and or other variables from the uri path.
   * @param [reportingIntervalInSeconds] override the reporting interval defaults to every 10 seconds.
   */
  onRequestEnd
};


================================================
FILE: packages/measured-node-metrics/lib/nodeHttpRequestMetrics.js
================================================
const { Stopwatch } = require('measured-core');

/**
 * The default reporting interval for requests
 * @type {number}
 */
const DEFAULT_REQUEST_METRICS_REPORTING_INTERVAL_IN_SECONDS = 10;

/**
 * This module has functions needed to create middlewares for frameworks such as express and koa.
 * It also exports the 2 functions needed to implement your own middleware.
 * If you implement a middleware for a framework not implemented here, please contribute it back.
 *
 * @module node-http-request-metrics
 */
module.exports = {
  /**
   * Creates an Express middleware that reports a timer on request data.
   * With this middleware you will get requests counts and latency percentiles all filterable by status codes, http method, and uri paths.
   *
   * @param {SelfReportingMetricsRegistry} metricsRegistry
   * @param {number} [reportingIntervalInSeconds]
   * @return {Function}
   */
  createExpressMiddleware: (metricsRegistry, reportingIntervalInSeconds) => {
    return (req, res, next) => {
      const stopwatch = module.exports.onRequestStart();

      res.on('finish', () => {
        const { method } = req;
        const { statusCode } = res;
        const uri = req.route ? req.route.path : '_unknown';
        module.exports.onRequestEnd(metricsRegistry, stopwatch, method, statusCode, uri, reportingIntervalInSeconds);
      });

      next();
    };
  },

  /**
   * Creates a Koa middleware that reports a timer on request data.
   * With this middleware you will get requests counts and latency percentiles all filterable by status codes, http method, and uri paths.
   *
   * @param {SelfReportingMetricsRegistry} metricsRegistry
   * @param {number} [reportingIntervalInSeconds]
   * @return {Function}
   */
  createKoaMiddleware: (metricsRegistry, reportingIntervalInSeconds) => async (ctx, next) => {
    const stopwatch = module.exports.onRequestStart();
    const { req, res } = ctx;

    res.once('finish', () => {
      const { method } = req;
      const { statusCode } = res;
      const uri = ctx._matchedRoute || '_unknown';
      module.exports.onRequestEnd(metricsRegistry, stopwatch, method, statusCode, uri, reportingIntervalInSeconds);
    });

    await next();
  },

  /**
   * At the start of the request, create a stopwatch, that starts tracking how long the request is taking.
   * @return {Stopwatch}
   */
  onRequestStart: () => {
    return new Stopwatch();
  },

  /**
   * When the request ends stop the stop watch and create or update the timer for requests that tracked by method, status code, path.
   * The timers (meters and histograms) that get reported will be filterable by status codes, http method, the uri path.
   * You will be able to create dash boards such as success percentage, latency percentiles by uri path and method, etc.
   *
   * @param {SelfReportingMetricsRegistry} metricsRegistry The Self Reporting Metrics Registry
   * @param {Stopwatch} stopwatch The stopwatch created by onRequestStart
   * @param {string} method The Http Method for the request
   * @param {string|number} statusCode The status code for the response
   * @param {string} [uri] The uri path for the request. Please note to avoid out of control time series dimension creation spread,
   * you would want to strip out ids and or other variables from the uri path.
   * @param {number} [reportingIntervalInSeconds] override the reporting interval defaults to every 10 seconds.
   */
  onRequestEnd: (metricsRegistry, stopwatch, method, statusCode, uri, reportingIntervalInSeconds) => {
    reportingIntervalInSeconds = reportingIntervalInSeconds || DEFAULT_REQUEST_METRICS_REPORTING_INTERVAL_IN_SECONDS;

    const customDimensions = {
      statusCode: `${statusCode}`,
      method: `${method}`
    };

    if (uri) {
      customDimensions.uri = uri;
    }

    // get or create the timer for the request count/latency timer
    const requestTimer = metricsRegistry.getOrCreateTimer('requests', customDimensions, reportingIntervalInSeconds);

    // stop the request latency counter
    const time = stopwatch.end();
    requestTimer.update(time);
  }
};


================================================
FILE: packages/measured-node-metrics/lib/nodeOsMetrics.js
================================================
const { Gauge, CachedGauge } = require('measured-core');
const { cpuAverage, calculateCpuUsagePercent } = require('./utils/CpuUtils');
const os = require('os');

/**
 * The default reporting interval for node os metrics is 30 seconds.
 *
 * @type {number}
 */
const DEFAULT_NODE_OS_METRICS_REPORTING_INTERVAL_IN_SECONDS = 30;

/**
 * A map of Metric generating functions, that create Metrics to measure node os stats.
 */
const nodeOsMetrics = {
  /**
   * https://nodejs.org/api/os.html#os_os_loadavg
   * @return {Gauge}
   */
  'node.os.loadavg.1m': () => {
    return new Gauge(() => {
      return os.loadavg()[0];
    });
  },
  /**
   * https://nodejs.org/api/os.html#os_os_loadavg
   * @return {Gauge}
   */
  'node.os.loadavg.5m': () => {
    return new Gauge(() => {
      return os.loadavg()[1];
    });
  },
  /**
   * https://nodejs.org/api/os.html#os_os_loadavg
   * @return {Gauge}
   */
  'node.os.loadavg.15m': () => {
    return new Gauge(() => {
      return os.loadavg()[2];
    });
  },
  'node.os.freemem': () => {
    return new Gauge(() => {
      return os.freemem();
    });
  },
  'node.os.totalmem': () => {
    return new Gauge(() => {
      return os.totalmem();
    });
  },

  /**
   * Gauge to track how long the os has been running.
   *\
   *]=-
   * See {@link https://nodejs.org/api/os.html#os_os_uptime} for more information.
   * @return {Gauge}
   */
  'node.os.uptime': () => {
    return new Gauge(() => {
      // The os.uptime() method returns the system uptime in number of seconds.
      return os.uptime();
    });
  },

  /**
   * Creates a {@link CachedGauge} that will self update every updateIntervalInSeconds and sample the
   * cpu usage across all cores for sampleTimeInSeconds.
   *
   * @param {number} [updateIntervalInSeconds] How often to update and cache the cpu usage average, defaults to 30 seconds.
   * @param {number} [sampleTimeInSeconds] How long to sample the cpu usage over, defaults to 5 seconds.
   */
  'node.os.cpu.all-cores-avg': (updateIntervalInSeconds, sampleTimeInSeconds) => {
    updateIntervalInSeconds = updateIntervalInSeconds || 30;
    sampleTimeInSeconds = sampleTimeInSeconds || 5;

    return new CachedGauge(() => {
      return new Promise(resolve => {
        //Grab first CPU Measure
        const startMeasure = cpuAverage();
        setTimeout(() => {
          //Grab second Measure
          const endMeasure = cpuAverage();
          const percentageCPU = calculateCpuUsagePercent(startMeasure, endMeasure);
          resolve(percentageCPU);
        }, sampleTimeInSeconds);
      });
    }, updateIntervalInSeconds);
  }
};

/**
 * This module contains the methods to create and register default node os metrics to a metrics registry.
 *
 * @module node-os-metrics
 */
module.exports = {
  /**
   * Method that can be used to add a set of default node process metrics to your app.
   *
   * @param {SelfReportingMetricsRegistry} metricsRegistry
   * @param {Dimensions} customDimensions
   * @param {number} reportingIntervalInSeconds
   */
  createOSMetrics: (metricsRegistry, customDimensions, reportingIntervalInSeconds) => {
    customDimensions = customDimensions || {};
    reportingIntervalInSeconds = reportingIntervalInSeconds || DEFAULT_NODE_OS_METRICS_REPORTING_INTERVAL_IN_SECONDS;

    Object.keys(nodeOsMetrics).forEach(metricName => {
      metricsRegistry.register(metricName, nodeOsMetrics[metricName](), customDimensions, reportingIntervalInSeconds);
    });
  },

  /**
   * Map of metric names to a corresponding function that creates and returns a Metric that tracks it.
   * See {@link nodeOsMetrics}
   */
  nodeOsMetrics
};


================================================
FILE: packages/measured-node-metrics/lib/nodeProcessMetrics.js
================================================
const { Gauge } = require('measured-core');
const process = require('process');

/**
 * The default reporting interval for node process metrics is 30 seconds.
 *
 * @type {number}
 */
const DEFAULT_NODE_PROCESS_METRICS_REPORTING_INTERVAL_IN_SECONDS = 30;

/**
 * A map of Metric generating functions, that create Metrics to measure node process stats.
 * @type {Object.<string, function>}
 */
const nodeProcessMetrics = {
  /**
   * Creates a gauge that reports the rss from the node memory usage api.
   * See {@link https://nodejs.org/api/process.html#process_process_memoryusage} for more information.
   *
   * @return {Gauge}
   */
  'node.process.memory-usage.rss': () => {
    return new Gauge(() => {
      return process.memoryUsage().rss;
    });
  },
  /**
   * See {@link https://nodejs.org/api/process.html#process_process_memoryusage} for more information.
   *
   * @return {Gauge}
   */
  'node.process.memory-usage.heap-total': () => {
    return new Gauge(() => {
      return process.memoryUsage().heapTotal;
    });
  },
  /**
   * See {@link https://nodejs.org/api/process.html#process_process_memoryusage} for more information.
   *
   * @return {Gauge}
   */
  'node.process.memory-usage.heap-used': () => {
    return new Gauge(() => {
      return process.memoryUsage().heapUsed;
    });
  },
  /**
   * See {@link https://nodejs.org/api/process.html#process_process_memoryusage} for more information.
   *
   * @return {Gauge}
   */
  'node.process.memory-usage.external': () => {
    return new Gauge(() => {
      const mem = process.memoryUsage();
      return Object.prototype.hasOwnProperty.call(mem, 'external') ? mem.external : 0;
    });
  },
  /**
   * Gauge to track how long the node process has been running.
   *
   * See {@link https://nodejs.org/api/process.html#process_process_uptime} for more information.
   * @return {Gauge}
   */
  'node.process.uptime': () => {
    return new Gauge(() => {
      return Math.floor(process.uptime());
    });
  }
};

/**
 * This module contains the methods to create and register default node process metrics to a metrics registry.
 *
 * @module node-process-metrics
 */
module.exports = {
  /**
   * Method that can be used to add a set of default node process metrics to your app.
   *
   * @param {SelfReportingMetricsRegistry} metricsRegistry
   * @param {Dimensions} [customDimensions]
   * @param {number} [reportingIntervalInSeconds]
   */
  createProcessMetrics: (metricsRegistry, customDimensions, reportingIntervalInSeconds) => {
    customDimensions = customDimensions || {};
    reportingIntervalInSeconds =
      reportingIntervalInSeconds || DEFAULT_NODE_PROCESS_METRICS_REPORTING_INTERVAL_IN_SECONDS;

    Object.keys(nodeProcessMetrics).forEach(metricName => {
      metricsRegistry.register(
        metricName,
        nodeProcessMetrics[metricName](),
        customDimensions,
        reportingIntervalInSeconds
      );
    });
  },

  /**
   * Map of metric names to a corresponding function that creates and returns a Metric that tracks it.
   * See {@link nodeProcessMetrics}
   */
  nodeProcessMetrics
};


================================================
FILE: packages/measured-node-metrics/lib/utils/CpuUtils.js
================================================
const os = require('os');

/**
 * @module CpuUtils
 */
module.exports = {
  /**
   *
   * @return {{idle: number, total: number}}
   */
  cpuAverage: () => {
    //Initialise sum of idle and time of cores and fetch CPU info
    let totalIdle = 0,
      totalTick = 0;
    const cpus = os.cpus();

    cpus.forEach(cpu => {
      //Total up the time in the cores tick
      Object.keys(cpu.times).forEach(type => {
        totalTick += cpu.times[type];
      });
      //Total up the idle time of the core
      totalIdle += cpu.times.idle;
    });

    //Return the average Idle and Tick times
    return { idle: totalIdle / cpus.length, total: totalTick / cpus.length };
  },

  /**
   *
   * @param {{idle: number, total: number}} startMeasure
   * @param {{idle: number, total: number}} endMeasure
   */
  calculateCpuUsagePercent: (startMeasure, endMeasure) => {
    //Calculate the difference in idle and total time between the measures
    const idleDifference = endMeasure.idle - startMeasure.idle;
    const totalDifference = endMeasure.total - startMeasure.total;
    //Calculate the average percentage CPU usage
    return Math.ceil(100 - 100 * idleDifference / totalDifference);
  }
};


================================================
FILE: packages/measured-node-metrics/package.json
================================================
{
  "name": "measured-node-metrics",
  "description": "Various metrics generators and http framework middlewares that can be used with a self reporting metrics registry to easily instrument metrics for a node app.",
  "version": "2.0.0",
  "homepage": "https://yaorg.github.io/node-measured/",
  "engines": {
    "node": ">= 5.12"
  },
  "publishConfig": {
    "access": "public"
  },
  "main": "./lib/index.js",
  "scripts": {
    "clean": "rm -fr build",
    "format": "prettier --write './lib/**/*.{ts,js}'",
    "lint": "eslint lib --ext .js",
    "test:node": "mocha './test/**/test-*.js'",
    "test:node:coverage": "nyc --report-dir build/coverage/ --reporter=html --reporter=text mocha './test/**/test-*.js'",
    "test:browser": "exit 0",
    "test": "yarn test:node:coverage",
    "coverage": "nyc report --reporter=text-lcov | coveralls"
  },
  "repository": {
    "url": "git://github.com/yaorg/node-measured.git"
  },
  "dependencies": {
    "measured-core": "^2.0.0"
  },
  "files": [
    "lib",
    "README.md"
  ],
  "license": "MIT",
  "devDependencies": {
    "express": "^4.16.3",
    "find-free-port": "^1.2.0",
    "jsdoc": "^3.5.5",
    "measured-reporting": "^2.0.0"
  }
}


================================================
FILE: packages/measured-node-metrics/test/integration/test-express-middleware.js
================================================
/*global describe, it, beforeEach, afterEach*/
const express = require('express');
const Registry = require('measured-reporting').SelfReportingMetricsRegistry;
const TestReporter = require('../unit/TestReporter');
const { createExpressMiddleware } = require('../../lib');
const findFreePort = require('find-free-port');
const assert = require('assert');
const http = require('http');

describe('express-middleware', () => {
  let port;
  let reporter;
  let registry;
  let middleware;
  let app;
  let httpServer;
  beforeEach(() => {
    return new Promise(resolve => {
      reporter = new TestReporter();
      registry = new Registry(reporter);
      middleware = createExpressMiddleware(registry, 1);
      app = express();
      app.use(middleware);
      app.use(express.json());

      app.get('/hello', (req, res) => res.send('Hello World!'));
      app.post('/world', (req, res) => res.status(201).send('Hello World!'));
      app.get('/users/:userId', (req, res) => {
        res.send(`id: ${req.params.userId}`);
      });

      findFreePort(3000).then(portArr => {
        port = portArr.shift();

        httpServer = http.createServer(app);
        httpServer.listen(port);
        resolve();
      });
    });
  });

  afterEach(() => {
    httpServer.close();
    registry.shutdown();
  });

  it('creates a single timer that has 1 count for requests, when an http call is made once', () => {
    return callLocalHost(port, 'hello').then(() => {
      const registeredKeys = registry._registry.allKeys();
      assert(registeredKeys.length === 1);
      assert.equal(registeredKeys[0], 'requests-GET-200-/hello');
      const metricWrapper = registry._registry.getMetricWrapperByKey('requests-GET-200-/hello');
      const { name, dimensions } = metricWrapper;
      assert.equal(name, 'requests');
      assert.deepEqual(dimensions, { statusCode: '200', method: 'GET', uri: '/hello' });
    });
  });

  it('creates a single timer that has 1 count for requests, when an http POST call is made once', () => {
    const options = { method: 'POST', headers: { 'Content-Type': 'application/json' } };
    return callLocalHost(port, 'world', options).then(() => {
      const registeredKeys = registry._registry.allKeys();
      assert(registeredKeys.length === 1);
      assert.equal(registeredKeys[0], 'requests-POST-201-/world');
      const metricWrapper = registry._registry.getMetricWrapperByKey('requests-POST-201-/world');
      const { name, dimensions } = metricWrapper;
      assert.equal(name, 'requests');
      assert.deepEqual(dimensions, { statusCode: '201', method: 'POST', uri: '/world' });
    });
  });

  it('does not create runaway n metrics in the registry for n ids in the path', () => {
    return Promise.all([
      callLocalHost(port, 'users/foo'),
      callLocalHost(port, 'users/bar'),
      callLocalHost(port, 'users/bop')
    ]).then(() => {
      assert.equal(registry._registry.allKeys().length, 1, 'There should only be one metric for /users and GET');
    });
  });
});

const callLocalHost = (port, endpoint, options) => {
  return new Promise((resolve, reject) => {
    const req = Object.assign({ protocol: 'http:',
      host: '127.0.0.1',
      port: `${port}`,
      path: `/${endpoint}`,
      method: 'GET' },
    options || {});
    http
      .request(req, resp => {
        let data = '';
        resp.on('data', chunk => {
          data += chunk;
        });

        resp.on('end', () => {
          console.log(JSON.stringify(data));
          resolve();
        });
      })
      .on('error', err => {
        console.log('Error: ', JSON.stringify(err));
        reject();
      })
      .end();
  });
};


================================================
FILE: packages/measured-node-metrics/test/integration/test-koa-middleware.js
================================================
const Koa = require('koa');
const KoaBodyParser = require('koa-bodyparser');
const Router = require('koa-router');
const Registry = require('measured-reporting').SelfReportingMetricsRegistry;
const TestReporter = require('../unit/TestReporter');
const { createKoaMiddleware } = require('../../lib');
const findFreePort = require('find-free-port');
const assert = require('assert');
const http = require('http');

describe('koa-middleware', () => {
  let port;
  let reporter;
  let registry;
  let middleware;
  let app;
  let httpServer;
  let router;
  beforeEach(() => {
    return new Promise(resolve => {
      reporter = new TestReporter();
      registry = new Registry(reporter);
      middleware = createKoaMiddleware(registry, 1);
      app = new Koa();
      router = new Router();

      router.get('/hello', ({ response }) => {
        response.body = 'Hello World!';
        return response;
      });
      router.post('/world', ({ response }) => {
        response.body = 'Hello World!';
        response.status = 201;
        return response;
      });
      router.get('/users/:userId', ({ params, response }) => {
        response.body = `id: ${params.userId}`;
        return response;
      });

      app.use(middleware);
      app.use(KoaBodyParser());
      app.use(router.routes());
      app.use(router.allowedMethods());

      app.on('error', (err) => console.error(err));

      findFreePort(3000).then(portArr => {
        port = portArr.shift();

        httpServer = app.listen(port);
        resolve();
      });
    });
  });

  afterEach(() => {
    httpServer.close();
    registry.shutdown();
  });

  it('creates a single timer that has 1 count for requests, when an http call is made once', () => {
    return callLocalHost(port, 'hello').then(() => {
      const registeredKeys = registry._registry.allKeys();
      assert(registeredKeys.length === 1);
      assert.equal(registeredKeys[0], 'requests-GET-200-/hello');
      const metricWrapper = registry._registry.getMetricWrapperByKey('requests-GET-200-/hello');
      const { name, dimensions } = metricWrapper;
      assert.equal(name, 'requests');
      assert.deepEqual(dimensions, { statusCode: '200', method: 'GET', uri: '/hello' });
    });
  });

  it('creates a single timer that has 1 count for requests, when an http POST call is made once', () => {
    const options = { method: 'POST', headers: { 'Content-Type': 'application/json' } };
    return callLocalHost(port, 'world', options).then(() => {
      const registeredKeys = registry._registry.allKeys();
      assert(registeredKeys.length === 1);
      assert.equal(registeredKeys[0], 'requests-POST-201-/world');
      const metricWrapper = registry._registry.getMetricWrapperByKey('requests-POST-201-/world');
      const { name, dimensions } = metricWrapper;
      assert.equal(name, 'requests');
      assert.deepEqual(dimensions, { statusCode: '201', method: 'POST', uri: '/world' });
    });
  });

  it('does not create runaway n metrics in the registry for n ids in the path', () => {
    return Promise.all([
      callLocalHost(port, 'users/foo'),
      callLocalHost(port, 'users/bar'),
      callLocalHost(port, 'users/bop')
    ]).then(() => {
      assert.equal(registry._registry.allKeys().length, 1, 'There should only be one metric for /users and GET');
    });
  });
});

const callLocalHost = (port, endpoint, options) => {
  return new Promise((resolve, reject) => {
    const req = Object.assign({ protocol: 'http:',
      host: '127.0.0.1',
      port: `${port}`,
      path: `/${endpoint}`,
      method: 'GET' },
    options || {});
    http
      .request(req, resp => {
        let data = '';
        resp.on('data', chunk => {
          data += chunk;
        });

        resp.on('end', () => {
          console.log(JSON.stringify(data));
          resolve();
        });
      })
      .on('error', err => {
        console.log('Error: ', JSON.stringify(err));
        reject();
      })
      .end();
  });
};


================================================
FILE: packages/measured-node-metrics/test/unit/TestReporter.js
================================================
const { Reporter } = require('measured-reporting');

/**
 * @extends Reporter
 */
class TestReporter extends Reporter {
  constructor(options) {
    super(options);

    this._reportedMetrics = [];
  }

  getReportedMetrics() {
    return this._reportedMetrics;
  }

  _reportMetrics(metrics) {
    this._reportedMetrics.push(metrics);
  }
}

module.exports = TestReporter;


================================================
FILE: packages/measured-node-metrics/test/unit/test-nodeHttpRequestMetrics.js
================================================
/*global describe, it, beforeEach, afterEach*/
const assert = require('assert');
const EventEmitter = require('events');
const { Stopwatch } = require('measured-core');
const { createExpressMiddleware, createKoaMiddleware, onRequestStart, onRequestEnd } = require('../../lib');
const TestReporter = require('./TestReporter');
const Registry = require('measured-reporting').SelfReportingMetricsRegistry;

class MockResponse extends EventEmitter {
  constructor() {
    super();
    this.statusCode = 200;
  }

  finish() {
    this.emit('finish');
  }
}

describe('onRequestStart', () => {
  it('returns a stopwatch', () => {
    const stopwatch = onRequestStart();
    assert(stopwatch.constructor.name === 'Stopwatch');
  });
});

describe('onRequestEnd', () => {
  it('stops the stopwatch and gets or creates a timer and then updates it with the elapsed time with the appropriate dimensions', () => {
    const stopwatch = new Stopwatch();
    const registry = new Registry(new TestReporter());

    onRequestEnd(registry, stopwatch, 'POST', 201, '/some/path');

    const registeredKeys = registry._registry.allKeys();
    assert(registeredKeys.length === 1);
    const expectedKey = 'requests-POST-201-/some/path';
    assert.equal(registeredKeys[0], expectedKey);
    const metricWrapper = registry._registry.getMetricWrapperByKey(expectedKey);
    assert.equal(metricWrapper.name, 'requests');
    assert.deepEqual(metricWrapper.dimensions, { statusCode: '201', method: 'POST', uri: '/some/path' });
    assert.equal(metricWrapper.metricImpl.getType(), 'Timer');
    assert.equal(metricWrapper.metricImpl._histogram._count, 1);
    registry.shutdown();
  });
});

describe('createExpressMiddleware', () => {
  it('creates and registers a metric called request that is a timer', () => {
    const reporter = new TestReporter();
    const registry = new Registry(reporter);

    const middleware = createExpressMiddleware(registry);

    const res = new MockResponse();
    middleware(
      {
        method: 'GET',
        routine: { path: '/v1/rest/some-end-point' }
      },
      res,
      () => {}
    );
    res.finish();

    const registeredKeys = registry._registry.allKeys();
    assert(registeredKeys.length === 1);
    assert(registeredKeys[0].includes('requests-GET'));
    registry.shutdown();
  });
});

describe('createKoaMiddleware', () => {
  it('creates and registers a metric called request that is a timer', async () => {
    const reporter = new TestReporter();
    const registry = new Registry(reporter);

    const middleware = createKoaMiddleware(registry);

    const res = new MockResponse();
    middleware(
      {
        req: {
          method: 'GET',
          url: '/v1/rest/some-end-point',
        },
        res,
      },
      () => Promise.resolve()
    ).then(() => {
      const registeredKeys = registry._registry.allKeys();
      assert(registeredKeys.length === 1);
      assert(registeredKeys[0].includes('requests-GET'));
      registry.shutdown();
    });
    res.finish();
  });
});


================================================
FILE: packages/measured-node-metrics/test/unit/test-nodeOsMetrics.js
================================================
/*global describe, it, beforeEach, afterEach*/
const assert = require('assert');
const { validateMetric } = require('measured-core').metricValidators;
const { nodeOsMetrics, createOSMetrics } = require('../../lib');
const TestReporter = require('./TestReporter');
const Registry = require('measured-reporting').SelfReportingMetricsRegistry;
const { MetricTypes } = require('measured-core');

describe('nodeOsMetrics', () => {
  it('contains a map of string to functions that generate a valid  metric object', () => {
    Object.keys(nodeOsMetrics).forEach(metricName => {
      assert(typeof metricName === 'string', 'The key should be a string');

      const metricGeneratingFunction = nodeOsMetrics[metricName];
      assert(typeof metricGeneratingFunction === 'function', 'metric generating function should be a function');

      const metric = metricGeneratingFunction();
      validateMetric(metric);

      const value = metric.toJSON();
      const type = metric.getType();
      if ([MetricTypes.COUNTER, MetricTypes.GAUGE].includes(type)) {
        assert(typeof value === 'number');
      } else {
        assert(typeof value === 'object');
      }

      if (metric.end) {
        metric.end();
      }
    });
  });
});

describe('createOSMetrics', () => {
  it('creates and registers a metric for every metric defined in nodeOsMetrics', () => {
    const reporter = new TestReporter();
    const registry = new Registry(reporter);

    createOSMetrics(registry);

    const registeredKeys = registry._registry.allKeys();
    const expectedKeys = Object.keys(nodeOsMetrics);
    assert(registeredKeys.length > 1);
    assert.deepEqual(registeredKeys, expectedKeys);

    registry.shutdown();
  });
});


================================================
FILE: packages/measured-node-metrics/test/unit/test-nodeProcessMetrics.js
================================================
/*global describe, it, beforeEach, afterEach*/
const assert = require('assert');
const { validateMetric } = require('measured-core').metricValidators;
const { nodeProcessMetrics, createProcessMetrics } = require('../../lib');
const TestReporter = require('./TestReporter');
const Registry = require('measured-reporting').SelfReportingMetricsRegistry;
const { MetricTypes } = require('measured-core');

describe('nodeProcessMetrics', () => {
  it('contains a map of string to functions that generate a valid  metric object', () => {
    Object.keys(nodeProcessMetrics).forEach(metricName => {
      assert(typeof metricName === 'string', 'The key should be a string');

      const metricGeneratingFunction = nodeProcessMetrics[metricName];
      assert(typeof metricGeneratingFunction === 'function', 'metric generating function should be a function');

      const metric = metricGeneratingFunction();
      validateMetric(metric);

      const value = metric.toJSON();
      const type = metric.getType();
      if ([MetricTypes.COUNTER, MetricTypes.GAUGE].includes(type)) {
        assert(typeof value === 'number');
      } else {
        assert(typeof value === 'object');
      }
    });
  });
});

describe('createProcessMetrics', () => {
  it('creates and registers a metric for every metric defined in nodeProcessMetrics', () => {
    const reporter = new TestReporter();
    const registry = new Registry(reporter);

    createProcessMetrics(registry);

    const registeredKeys = registry._registry.allKeys();
    const expectedKeys = Object.keys(nodeProcessMetrics);
    assert(registeredKeys.length > 1);
    assert.deepEqual(registeredKeys, expectedKeys);

    registry.shutdown();
  });
});


================================================
FILE: packages/measured-node-metrics/test/unit/utils/test-CpuUtils.js
================================================
/*global describe, it, beforeEach, afterEach*/
const assert = require('assert');
const CpuUtils = require('../../../lib/utils/CpuUtils');

describe('CpuUtils', () => {
  it('#cpuAverage ', () => {
    const measure = CpuUtils.cpuAverage();
    assert(typeof measure.idle === 'number');
    assert(measure.idle > 0);

    assert(typeof measure.total === 'number');
    assert(measure.total > 0);
  });

  it('#calculateCpuUsagePercent calculates a percent', () => {
    const start = CpuUtils.cpuAverage();

    for (let i = 0; i < 10000000; i++) {
      Math.floor(Math.random() * Math.floor(10000000));
    }

    const end = CpuUtils.cpuAverage();
    const percent = CpuUtils.calculateCpuUsagePercent(start, end);
    assert(typeof percent === 'number');
    assert(percent > 0);
  });
});


================================================
FILE: packages/measured-reporting/README.md
================================================
# Measured Reporting

The registry and reporting library that has the classes needed to create a dimension aware, self reporting metrics registry.

[![npm](https://img.shields.io/npm/v/measured-reporting.svg)](https://www.npmjs.com/package/measured-reporting) 

## Install

```
npm install measured-reporting
```

## What is in this package

### [Self Reporting Metrics Registry](https://yaorg.github.io/node-measured/SelfReportingMetricsRegistry.html)
A dimensional aware self-reporting metrics registry, just supply this class with a reporter implementation at instantiation and this is all you need to instrument application level metrics in your app.

See the [SelfReportingMetricsRegistryOptions](https://yaorg.github.io/node-measured/global.html#SelfReportingMetricsRegistryOptions) for advanced configuration.

```javascript
const { SelfReportingMetricsRegistry, LoggingReporter } = require('measured-reporting');
const registry = new SelfReportingMetricsRegistry(new LoggingReporter({
  defaultDimensions: {
    hostname: os.hostname()
  }
}));

// The metric will flow through LoggingReporter#_reportMetrics(metrics) every 10 seconds by default
const myCounter = registry.getOrCreateCounter('my-counter');

```

### [Reporter Abstract Class](https://yaorg.github.io/node-measured/Reporter.html)
Extend this class and override the [_reportMetrics(metrics)](https://yaorg.github.io/node-measured/Reporter.html#_reportMetrics__anchor) method to create a vendor specific reporter implementation. 

See the [ReporterOptions](https://yaorg.github.io/node-measured/global.html#ReporterOptions) for advanced configuration.

#### Current Implementations
- [SignalFx Reporter](https://yaorg.github.io/node-measured/SignalFxMetricsReporter.html) in the `measured-signalfx-reporter` package.
  - reports metrics to SignalFx.
- [Logging Reporter](https://yaorg.github.io/node-measured/LoggingReporter.html) in the `measured-reporting` package.
  - A reporter impl that simply logs the metrics via the Logger

#### Creating an anonymous Implementation
You can technically create an anonymous instance of this, see the following example.
```javascript
const os = require('os');
const process = require('process');
const { SelfReportingMetricsRegistry, Reporter } = require('measured-reporting');

// Create a self reporting registry with an anonymous Reporter instance;
const registry = new SelfReportingMetricsRegistry(
  new class extends Reporter {
    constructor() {
      super({
        defaultDimensions: {
          hostname: os.hostname(),
          env: process.env['NODE_ENV'] ? process.env['NODE_ENV'] : 'unset'
        }
      })
    }

    _reportMetrics(metrics) {
      metrics.forEach(metric => {
        console.log(JSON.stringify({
          metricName: metric.name,
          dimensions: this._getDimensions(metric),
          data: metric.metricImpl.toJSON()
        }))
      });
    }
  }()
);

// create a gauge that reports the process uptime every second
const processUptimeGauge = registry.getOrCreateGauge('node.process.uptime', () => process.uptime(), {}, 1);
```

Example output:
```bash
APP5HTD6ACCD8C:foo jfiel2$ NODE_ENV=development node index.js
{"metricName":"node.process.uptime","dimensions":{"hostname":"APP5HTD6ACCD8C","env":"development"},"data":0.092}
{"metricName":"node.process.uptime","dimensions":{"hostname":"APP5HTD6ACCD8C","env":"development"},"data":1.099}
{"metricName":"node.process.uptime","dimensions":{"hostname":"APP5HTD6ACCD8C","env":"development"},"data":2.104}
{"metricName":"node.process.uptime","dimensions":{"hostname":"APP5HTD6ACCD8C","env":"development"},"data":3.105}
{"metricName":"node.process.uptime","dimensions":{"hostname":"APP5HTD6ACCD8C","env":"development"},"data":4.106}
```


Consider creating a proper class and contributing it back to Measured if it is generic and sharable.

### [Logging Reporter Class](https://yaorg.github.io/node-measured/LoggingReporter.html)
A simple reporter that logs the metrics via the Logger.

See the [ReporterOptions](http://yaorg.github.io/node-measured/build/docs/packages/measured-reporting/global.html#ReporterOptions) for advanced configuration.

```javascript
const { SelfReportingMetricsRegistry, LoggingReporter } = require('measured-reporting');
const registry = new SelfReportingMetricsRegistry(new LoggingReporter({
  logger: myLogerImpl, // defaults to new console logger if not supplied
  defaultDimensions: {
    hostname: require('os').hostname()
  }
}));
```

## What are dimensions?
As described by Signal Fx:
    
*A dimension is a key/value pair that, along with the metric name, is part of the identity of a time series. 
You can filter and aggregate time series by those dimensions across SignalFx.*
    
DataDog has a [nice blog post](https://www.datadoghq.com/blog/the-power-of-tagged-metrics/) about how they are used in their aggregator api.

Graphite also supports the concept via [tags](http://graphite.readthedocs.io/en/latest/tags.html).



================================================
FILE: packages/measured-reporting/lib/@types/types.js
================================================
/**
 * A wrapper object around a {@link Metric}, {@link Dimensions} and the metric name
 *
 * @interface MetricWrapper
 * @typedef MetricWrapper
 * @type {Object}
 * @property {string} name The supplied name of the Metric
 * @property {Metric} metricImpl The {@link Metric} object
 * @property {Dimensions} dimensions The {@link Dimensions} for the given {@link Metric}
 */

/**
 * A Dictionary of string, string key value pairs
 *
 * @interface Dimensions
 * @typedef Dimensions
 * @type {Object.<string, string>}
 *
 * @example
 * {
 *   path: "/api/foo"
 *   method: "GET"
 *   statusCode: "200"
 * }
 */


================================================
FILE: packages/measured-reporting/lib/index.js
================================================
const SelfReportingMetricsRegistry = require('./registries/SelfReportingMetricsRegistry');
const Reporter = require('./reporters/Reporter');
const LoggingReporter = require('./reporters/LoggingReporter');
const inputValidators = require('./validators/inputValidators');

/**
 * The main measured module that is referenced when require('measured-reporting') is used.
 * @module measured-reporting
 */
module.exports = {
  /**
   * The Self Reporting Metrics Registry Class.
   *
   * @type {SelfReportingMetricsRegistry}
   */
  SelfReportingMetricsRegistry,

  /**
   * The abstract / base Reporter class.
   *
   * @type {Reporter}
   */
  Reporter,

  /**
   * The basic included reference reporter, simply logs the metrics.
   * See {ReporterOptions} for options.
   *
   * @type {LoggingReporter}
   */
  LoggingReporter,

  /**
   * Various Input Validation functions.
   *
   * @type {inputValidators}
   */
  inputValidators
};


================================================
FILE: packages/measured-reporting/lib/registries/DimensionAwareMetricsRegistry.js
================================================
const mapcap = require('mapcap');

/**
 * Simple registry that stores Metrics by name and dimensions.
 */
class DimensionAwareMetricsRegistry {
  /**
   * @param {DimensionAwareMetricsRegistryOptions} [options] Configurable options for the Dimension Aware Metrics Registry
   */
  constructor(options) {
    options = options || {};

    let metrics = new Map();
    if (options.metricLimit) {
      metrics = mapcap(metrics, options.metricLimit, options.lru);
    }

    this._metrics = metrics;
  }

  /**
   * Checks to see if a metric with the given name and dimensions is present.
   *
   * @param {string} name The metric name
   * @param {Dimensions} dimensions The dimensions for the metric
   * @returns {boolean} true if the metric with given dimensions is present
   */
  hasMetric(name, dimensions) {
    const key = this._generateStorageKey(name, dimensions);
    return this._metrics.has(key);
  }

  /**
   * Retrieves a metric with a given name and dimensions is present.
   *
   * @param {string} name The metric name
   * @param {Dimensions} dimensions The dimensions for the metric
   * @returns {Metric} a wrapper object around name, dimension and {@link Metric}
   */
  getMetric(name, dimensions) {
    const key = this._generateStorageKey(name, dimensions);
    return this._metrics.get(key).metricImpl;
  }

  /**
   * Retrieves a metric by the calculated key (name / dimension combo).
   *
   * @param {string} key The registered key for the given registered {@link MetricWrapper}
   * @returns {MetricWrapper} a wrapper object around name, dimension and {@link Metric}
   */
  getMetricWrapperByKey(key) {
    return this._metrics.get(key);
  }

  /**
   * Upserts a {@link Metric} in the internal storage map for a given name, dimension combo
   *
   * @param {string} name The metric name
   * @param {Metric} metric The {@link Metric} impl
   * @param {Dimensions} dimensions The dimensions for the metric
   * @return {string} The registry key for the metric, dimension combo
   */
  putMetric(name, metric, dimensions) {
    const key = this._generateStorageKey(name, dimensions);
    this._metrics.set(key, {
      name: name,
      metricImpl: metric,
      dimensions: dimensions || {}
    });
    return key;
  }

  /**
   * Returns an array of all keys of metrics stored in this registry.
   * @return {string[]} all keys of metrics stored in this registry.
   */
  allKeys() {
    return Array.from(this._metrics.keys());
  }

  /**
   * Generates a unique key off of the metric name and custom dimensions for internal use in the registry maps.
   *
   * @param {string} name The metric name
   * @param {Dimensions} dimensions The dimensions for the metric
   * @return {string} a unique key based off of the metric nae and dimensions
   * @private
   */
  _generateStorageKey(name, dimensions) {
    let key = name;
    if (dimensions) {
      Object.keys(dimensions)
        .sort()
        .forEach(dimensionKey => {
          key = `${key}-${dimensions[dimensionKey]}`;
        });
    }
    return key;
  }
}

module.exports = DimensionAwareMetricsRegistry;

/**
 * Configurable options for the Dimension Aware Metrics Registry
 *
 * @interface DimensionAwareMetricsRegistryOptions
 * @typedef DimensionAwareMetricsRegistryOptions
 * @property {Number} metricLimit the maximum number of metrics the registry may hold before dropping metrics
 * @property {Boolean} lru switch dropping strategy from "least recently added" to "least recently used"
 */


================================================
FILE: packages/measured-reporting/lib/registries/SelfReportingMetricsRegistry.js
================================================
const consoleLogLevel = require('console-log-level');
const { CachedGauge, SettableGauge, Gauge, Timer, Counter, Meter, Histogram } = require('measured-core');
const DimensionAwareMetricsRegistry = require('./DimensionAwareMetricsRegistry');
const {
  validateSelfReportingMetricsRegistryParameters,
  validateRegisterOptions,
  validateGaugeOptions,
  validateCounterOptions,
  validateHistogramOptions,
  validateTimerOptions,
  validateSettableGaugeOptions,
  validateCachedGaugeOptions
} = require('../validators/inputValidators');

function prefix() {
  return `${new Date().toISOString()}: `;
}

/**
 * A dimensional aware self-reporting metrics registry
 */
class SelfReportingMetricsRegistry {
  /**
   * @param {Reporter|Reporter[]} reporters A single {@link Reporter} or an array of reporters that will be used to report metrics on an interval.
   * @param {SelfReportingMetricsRegistryOptions} [options] Configurable options for the Self Reporting Metrics Registry
   */
  constructor(reporters, options) {
    options = options || {};

    if (!Array.isArray(reporters)) {
      reporters = [reporters];
    }

    validateSelfReportingMetricsRegistryParameters(reporters, options);

    /**
     * @type {Reporter}
     * @protected
     */
    this._reporters = reporters;

    /**
     * @type {DimensionAwareMetricsRegistry}
     * @protected
     */
    this._registry = options.registry || new DimensionAwareMetricsRegistry();
    this._reporters.forEach(reporter => reporter.setRegistry(this._registry));

    /**
     * Loggers to use, defaults to a new console logger if nothing is supplied in options
     * @type {Logger}
     * @protected
     */
    this._log =
      options.logger ||
      consoleLogLevel({ name: 'SelfReportingMetricsRegistry', level: options.logLevel || 'info', prefix: prefix });
  }

  /**
   * Registers a manually created Metric.
   *
   * @param {string} name The Metric name
   * @param {Metric} metric The {@link Metric} to register
   * @param {Dimensions} [dimensions] any custom {@link Dimensions} for the Metric
   * @param {number} [publishingIntervalInSeconds] a optional custom publishing interval
   * @example
   * const settableGauge = new SettableGauge(5);
   * // register the gauge and have it report to every 10 seconds
   * registry.register('my-gauge', settableGauge, {}, 10);
   * interval(() => {
   *    // such as cpu % used
   *    determineAValueThatCannotBeSync((value) => {
   *      settableGauge.update(value);
   *    })
   * }, 10000)
   */
  register(name, metric, dimensions, publishingIntervalInSeconds) {
    validateRegisterOptions(name, metric, dimensions, publishingIntervalInSeconds);

    if (this._registry.hasMetric(name, dimensions)) {
      throw new Error(
        `Metric with name: ${name} and dimensions: ${JSON.stringify(dimensions)} has already been registered`
      );
    } else {
      const key = this._registry.putMetric(name, metric, dimensions);
      this._reporters.forEach(reporter => reporter.reportMetricOnInterval(key, publishingIntervalInSeconds));
    }
    return metric;
  }

  /**
   * Creates a {@link Gauge} or gets the existing Gauge for a given name and dimension combo
   *
   * @param {string} name The Metric name
   * @param {function} callback The callback that will return a value to report to signal fx
   * @param {Dimensions} [dimensions] any custom {@link Dimensions} for the Metric
   * @param {number} [publishingIntervalInSeconds] a optional custom publishing interval
   * @return {Gauge}
   * @example
   * // https://nodejs.org/api/process.html#process_process_memoryusage
   * // Report heap total and heap used at the default interval
   * registry.getOrCreateGauge(
   *   'process-memory-heap-total',
   *   () => {
   *     return process.memoryUsage().heapTotal
   *   }
   * );
   * registry.getOrCreateGauge(
   *   'process-memory-heap-used',
   *   () => {
   *     return process.memoryUsage().heapUsed
   *   }
   * )
   */
  getOrCreateGauge(name, callback, dimensions, publishingIntervalInSeconds) {
    validateGaugeOptions(name, callback, dimensions, publishingIntervalInSeconds);
    let gauge;
    if (this._registry.hasMetric(name, dimensions)) {
      gauge = this._registry.getMetric(name, dimensions);
    } else {
      gauge = new Gauge(callback);
      const key = this._registry.putMetric(name, gauge, dimensions);
      this._reporters.forEach(reporter => reporter.reportMetricOnInterval(key, publishingIntervalInSeconds));
    }
    return gauge;
  }

  /**
   * Creates a {@link Histogram} or gets the existing Histogram for a given name and dimension combo
   *
   * @param {string} name The Metric name
   * @param {Dimensions} [dimensions] any custom {@link Dimensions} for the Metric
   * @param {number} [publishingIntervalInSeconds] a optional custom publishing interval
   * @return {Histogram}
   */
  getOrCreateHistogram(name, dimensions, publishingIntervalInSeconds) {
    validateHistogramOptions(name, dimensions, publishingIntervalInSeconds);

    let histogram;
    if (this._registry.hasMetric(name, dimensions)) {
      histogram = this._registry.getMetric(name, dimensions);
    } else {
      histogram = new Histogram();
      const key = this._registry.putMetric(name, histogram, dimensions);
      this._reporters.forEach(reporter => reporter.reportMetricOnInterval(key, publishingIntervalInSeconds));
    }

    return histogram;
  }

  /**
   * Creates a {@link Meter} or gets the existing Meter for a given name and dimension combo
   *
   * @param {string} name The Metric name
   * @param {Dimensions} [dimensions] any custom {@link Dimensions} for the Metric
   * @param {number} [publishingIntervalInSeconds] a optional custom publishing interval
   * @return {Meter}
   */
  getOrCreateMeter(name, dimensions, publishingIntervalInSeconds) {
    // todo validate options
    let meter;
    if (this._registry.hasMetric(name, dimensions)) {
      meter = this._registry.getMetric(name, dimensions);
    } else {
      meter = new Meter();
      const key = this._registry.putMetric(name, meter, dimensions);
      this._reporters.forEach(reporter => reporter.reportMetricOnInterval(key, publishingIntervalInSeconds));
    }

    return meter;
  }

  /**
   * Creates a {@link Counter} or gets the existing Counter for a given name and dimension combo
   *
   * @param {string} name The Metric name
   * @param {Dimensions} [dimensions] any custom {@link Dimensions} for the Metric
   * @param {number} [publishingIntervalInSeconds] a optional custom publishing interval
   * @return {Counter}
   */
  getOrCreateCounter(name, dimensions, publishingIntervalInSeconds) {
    validateCounterOptions(name, dimensions, publishingIntervalInSeconds);

    let counter;
    if (this._registry.hasMetric(name, dimensions)) {
      counter = this._registry.getMetric(name, dimensions);
    } else {
      counter = new Counter();
      const key = this._registry.putMetric(name, counter, dimensions);
      this._reporters.forEach(reporter => reporter.reportMetricOnInterval(key, publishingIntervalInSeconds));
    }

    return counter;
  }

  /**
   * Creates a {@link Timer} or gets the existing Timer for a given name and dimension combo.
   *
   * @param {string} name The Metric name
   * @param {Dimensions} [dimensions] any custom {@link Dimensions} for the Metric
   * @param {number} [publishingIntervalInSeconds] a optional custom publishing interval
   * @return {Timer}
   */
  getOrCreateTimer(name, dimensions, publishingIntervalInSeconds) {
    validateTimerOptions(name, dimensions, publishingIntervalInSeconds);

    let timer;
    if (this._registry.hasMetric(name, dimensions)) {
      timer = this._registry.getMetric(name, dimensions);
    } else {
      timer = new Timer();
      const key = this._registry.putMetric(name, timer, dimensions);
      this._reporters.forEach(reporter => reporter.reportMetricOnInterval(key, publishingIntervalInSeconds));
    }

    return timer;
  }

  /**
   * Creates a {@link SettableGauge} or gets the existing SettableGauge for a given name and dimension combo.
   *
   * @param {string} name The Metric name
   * @param {Dimensions} [dimensions] any custom {@link Dimensions} for the Metric
   * @param {number} [publishingIntervalInSeconds] a optional custom publishing interval
   * @return {SettableGauge}
   */
  getOrCreateSettableGauge(name, dimensions, publishingIntervalInSeconds) {
    validateSettableGaugeOptions(name, dimensions, publishingIntervalInSeconds);

    let settableGauge;
    if (this._registry.hasMetric(name, dimensions)) {
      settableGauge = this._registry.getMetric(name, dimensions);
    } else {
      settableGauge = new SettableGauge();
      const key = this._registry.putMetric(name, settableGauge, dimensions);
      this._reporters.forEach(reporter => reporter.reportMetricOnInterval(key, publishingIntervalInSeconds));
    }

    return settableGauge;
  }

  /**
   * Creates a {@link CachedGauge} or gets the existing CachedGauge for a given name and dimension combo.
   *
   * @param {string} name The Metric name.
   * @param {function} valueProducingPromiseCallback.
   * @param {number} cachedGaugeUpdateIntervalInSeconds.
   * @param {Dimensions} [dimensions] any custom {@link Dimensions} for the Metric.
   * @param {number} [publishingIntervalInSeconds] a optional custom publishing interval.
   * @return {CachedGauge}
   */
  getOrCreateCachedGauge(
    name,
    valueProducingPromiseCallback,
    cachedGaugeUpdateIntervalInSeconds,
    dimensions,
    publishingIntervalInSeconds
  ) {
    validateCachedGaugeOptions(name, valueProducingPromiseCallback, dimensions, publishingIntervalInSeconds);

    let cachedGauge;
    if (this._registry.hasMetric(name, dimensions)) {
      cachedGauge = this._registry.getMetric(name, dimensions);
    } else {
      cachedGauge = new CachedGauge(valueProducingPromiseCallback, cachedGaugeUpdateIntervalInSeconds);
      const key = this._registry.putMetric(name, cachedGauge, dimensions);
      this._reporters.forEach(reporter => reporter.reportMetricOnInterval(key, publishingIntervalInSeconds));
    }

    return cachedGauge;
  }

  /**
   * Calls end on all metrics in the registry that support end() and calls end on the reporter
   */
  shutdown() {
    // shutdown the reporter
    this._reporters.forEach(reporter => reporter.shutdown());
    // shutdown any metrics that have an end method
    this._registry.allKeys().forEach(key => {
      const metricWrapper = this._registry.getMetricWrapperByKey(key);
      if (metricWrapper.metricImpl.end) {
        metricWrapper.metricImpl.end();
      }
    });
  }
}

module.exports = SelfReportingMetricsRegistry;

/**
 * Configurable options for the Self Reporting Metrics Registry
 *
 * @interface SelfReportingMetricsRegistryOptions
 * @typedef SelfReportingMetricsRegistryOptions
 * @property {Logger} logger the Logger to use
 * @property {string} logLevel The Log level to use if defaulting to included logger
 * @property {DimensionAwareMetricsRegistry} registry The registry to use, defaults to new DimensionAwareMetricsRegistry
 */


================================================
FILE: packages/measured-reporting/lib/reporters/LoggingReporter.js
================================================
const Reporter = require('./Reporter');

/**
 * A reporter impl that simply logs the metrics via the Logger.
 *
 * @example
 * const { SelfReportingMetricsRegistry, LoggingReporter } = require('measured-reporting');
 * const registry = new SelfReportingMetricsRegistry(new LoggingReporter());
 *
 * @extends {Reporter}
 */
class LoggingReporter extends Reporter {
  /**
   * @param {LoggingReporterOptions} [options]
   */
  constructor(options) {
    super(options);
    const level = (options || {}).logLevelToLogAt;
    this._logLevel = (level || 'info').toLowerCase();
  }

  /**
   * Logs the metrics via the inherited logger instance.
   * @param {MetricWrapper[]} metrics
   * @protected
   */
  _reportMetrics(metrics) {
    metrics.forEach(metric => {
      this._log[this._logLevel](
        JSON.stringify({
          metricName: metric.name,
          dimensions: this._getDimensions(metric),
          data: metric.metricImpl.toJSON()
        })
      );
    });
  }
}

module.exports = LoggingReporter;

/**
 * @interface LoggingReporterOptions
 * @typedef LoggingReporterOptions
 * @type {Object}
 * @property {Dimensions} defaultDimensions A dictionary of dimensions to include with every metric reported
 * @property {Logger} [logger] The logger to use, if not supplied a new Buynan logger will be created
 * @property {string} [logLevel] The log level to use with the created console logger if you didn't supply your own logger.
 * @property {number} [defaultReportingIntervalInSeconds] The default reporting interval to use if non is supplied when registering a metric, defaults to 10 seconds.
 * @property {string} [logLevelToLogAt] You can specify the log level ['debug', 'info', 'warn', 'error'] that this reporter will use when logging the metrics via the logger.
 */


================================================
FILE: packages/measured-reporting/lib/reporters/Reporter.js
================================================
const consoleLogLevel = require('console-log-level');
const Optional = require('optional-js');
const { validateReporterParameters } = require('../validators/inputValidators');

const DEFAULT_REPORTING_INTERVAL_IN_SECONDS = 10;

function prefix() {
  return `${new Date().toISOString()}: `;
}

/**
 * The abstract reporter that specific implementations can extend to create a Self Reporting Metrics Registry Reporter.
 *
 * {@link SelfReportingMetricsRegistry}
 *
 * @example
 * const os = require('os');
 * const process = require('process');
 * const { SelfReportingMetricsRegistry, Reporter } = require('measured-reporting');
 *
 * // Create a self reporting registry with a named anonymous reporter instance;
 * const registry = new SelfReportingMetricsRegistry(
 *   new class ConsoleReporter extends Reporter {
 *     constructor() {
 *       super({
 *         defaultDimensions: {
 *           hostname: os.hostname(),
 *           env: process.env['NODE_ENV'] ? process.env['NODE_ENV'] : 'unset'
 *         }
 *        })
 *     }
 *
 *     _reportMetrics(metrics) {
 *        metrics.forEach(metric => {
 *          console.log(JSON.stringify({
 *            metricName: metric.name,
 *            dimensions: this._getDimensions(metric),
 *            data: metric.metricImpl.toJSON()
 *           }))
 *       });
 *     }
 *  }()
 * );
 *
 * @example
 * // Create a regular class that extends Reporter
 * class LoggingReporter extends Reporter {
 *   _reportMetrics(metrics) {
 *     metrics.forEach(metric => {
 *       this._log.info(JSON.stringify({
 *        metricName: metric.name,
 *        dimensions: this._getDimensions(metric),
 *        data: metric.metricImpl.toJSON()
 *       }))
 *     });
 *   }
 * }
 *
 * @abstract
 */
class Reporter {
  /**
   * @param {ReporterOptions} [options] The optional params to supply when creating a reporter.
   */
  constructor(options) {
    if (this.constructor === Reporter) {
      throw new TypeError("Can't instantiate abstract class!");
    }

    options = options || {};
    validateReporterParameters(options);

    /**
     * Map of intervals to metric keys, this will be used to look up what metrics should be reported at a given interval.
     *
     * @type {Object.<number, Set<string>>}
     * @private
     */
    this._intervalToMetric = {};
    this._intervals = [];

    /**
     * Map of default dimensions, that should be sent with every metric.
     *
     * @type {Dimensions}
     * @protected
     */
    this._defaultDimensions = options.defaultDimensions || {};

    /**
     * Loggers to use, defaults to a new console logger if nothing is supplied in options
     * @type {Logger}
     * @protected
     */
    this._log =
      options.logger || consoleLogLevel({ name: 'Reporter', level: options.logLevel || 'info', prefix: prefix });

    /**
     * The default reporting interval, a number in seconds.
     * If not overridden via the {@see ReporterOptions}, defaults to 10 seconds.
     *
     * @type {number}
     * @protected
     */
    this._defaultReportingIntervalInSeconds =
      options.defaultReportingIntervalInSeconds || DEFAULT_REPORTING_INTERVAL_IN_SECONDS;

    /**
     * Flag to indicate if reporting timers should be unref'd.
     * If not overridden via the {@see ReporterOptions}, defaults to false.
     *
     * @type {boolean}
     * @protected
     */
    this._unrefTimers = !!options.unrefTimers;

    /**
     * Flag to indicate if metrics should be reset on each reporting interval.
     * If not overridden via the {@see ReporterOptions}, defaults to false.
     *
     * @type {boolean}
     * @protected
     */
    this._resetMetricsOnInterval = !!options.resetMetricsOnInterval;
  }

  /**
   * Sets the registry, this must be called before reportMetricOnInterval.
   *
   * @param {DimensionAwareMetricsRegistry} registry
   */
  setRegistry(registry) {
    this._registry = registry;
  }

  /**
   * Informs the reporter to report a metric on a given interval in seconds.
   *
   * @param {string} metricKey The metric key for the metric in the metric registry.
   * @param {number} intervalInSeconds The interval in seconds to report the metric on.
   */
  reportMetricOnInterval(metricKey, intervalInSeconds) {
    intervalInSeconds = intervalInSeconds || this._defaultReportingIntervalInSeconds;

    if (!this._registry) {
      throw new Error(
        'You must call setRegistry(registry) before telling a Reporter to report a metric on an interval.'
      );
    }

    if (Object.prototype.hasOwnProperty.call(this._intervalToMetric, intervalInSeconds)) {
      this._intervalToMetric[intervalInSeconds].add(metricKey);
    } else {
      this._intervalToMetric[intervalInSeconds] = new Set([metricKey]);
      this._createIntervalCallback(intervalInSeconds);
      setImmediate(() => {
        this._reportMetricsWithInterval(intervalInSeconds);
      });
    }
  }

  /**
   * Creates the timed callback loop for the given interval.
   *
   * @param {number} intervalInSeconds the interval in seconds for the timeout callback
   * @private
   */
  _createIntervalCallback(intervalInSeconds) {
    this._log.debug(`_createIntervalCallback() called with intervalInSeconds: ${intervalInSeconds}`);

    const timer = setInterval(() => {
      this._reportMetricsWithInterval(intervalInSeconds);
    }, intervalInSeconds * 1000);

    if (this._unrefTimers) {
      timer.unref();
    }

    this._intervals.push(timer);
  }

  /**
   * Gathers all the metrics that have been registered to report on the given interval.
   *
   * @param {number} interval The interval to look up what metrics to report
   * @private
   */
  _reportMetricsWithInterval(interval) {
    this._log.debug(`_reportMetricsWithInterval() called with intervalInSeconds: ${interval}`);
    try {
      Optional.of(this._intervalToMetric[interval]).ifPresent(metrics => {
        const metricsToSend = [];
        metrics.forEach(metricKey => {
          metricsToSend.push(this._registry.getMetricWrapperByKey(metricKey));
        });
        this._reportMetrics(metricsToSend);

        if (this._resetMetricsOnInterval) {
          metricsToSend.forEach(({ name, metricImpl }) => {
            if (metricImpl && metricImpl.reset) {
              this._log.debug('Resetting metric', name);
              metricImpl.reset();
            }
          });
        }
      });
    } catch (error) {
      this._log.error('Failed to send metrics to signal fx', error);
    }
  }

  /**
   * This method gets called with an array of {@link MetricWrapper} on an interval, when metrics should be reported.
   *
   * This is the main method that needs to get implemented when created an aggregator specific reporter.
   *
   * @param {MetricWrapper[]} metrics The array of metrics to report.
   * @protected
   * @abstract
   */
  _reportMetrics(metrics) {
    throw new TypeError('Abstract method _reportMetrics(metrics) must be implemented in implementation class');
  }

  /**
   *
   * @param {MetricWrapper} metric The Wrapped Metric Object.
   * @return {Dimensions} The left merged default dimensions with the metric specific dimensions
   * @protected
   */
  _getDimensions(metric) {
    return Object.assign({}, this._defaultDimensions, metric.dimensions);
  }

  /**
   * Clears the intervals that are running to report metrics at an interval, and resets the state.
   */
  shutdown() {
    this._intervals.forEach(interval => clearInterval(interval));
    this._intervals = [];
    this._intervalToMetric = {};
  }
}

/**
 * Options for creating a {@link Reporter}
 * @interface ReporterOptions
 * @typedef ReporterOptions
 * @type {Object}
 * @property {Dimensions} defaultDimensions A dictionary of dimensions to include with every metric reported
 * @property {Logger} logger The logger to use, if not supplied a new Buynan logger will be created
 * @property {string} logLevel The log level to use with the created console logger if you didn't supply your own logger.
 * @property {number} defaultReportingIntervalInSeconds The default reporting interval to use if non is supplied when registering a metric, defaults to 10 seconds.
 * @property {boolean} unrefTimers Indicate if reporting timers should be unref'd, defaults to false.
 * @property {boolean} resetMetricsOnInterval Indicate if metrics should be reset on each reporting interval, defaults to false.
 */

module.exports = Reporter;


================================================
FILE: packages/measured-reporting/lib/validators/inputValidators.js
================================================
const Optional = require('optional-js');
const { validateMetric } = require('measured-core').metricValidators;

/**
 * This module contains various validators to validate publicly exposed input.
 *
 * @module inputValidators
 */
module.exports = {
  /**
   * Validates @{link Gauge} options.
   *
   * @param {string} name The metric name
   * @param {function} callback The callback for the Gauge
   * @param {Dimensions} dimensions The optional custom dimensions
   * @param {number} publishingIntervalInSeconds the optional publishing interval
   */
  validateGaugeOptions: (name, callback, dimensions, publishingIntervalInSeconds) => {
    module.exports.validateCommonMetricParameters(name, dimensions, publishingIntervalInSeconds);
    module.exports.validateNumberReturningCallback(callback);
  },

  /**
   * Validates @{link Gauge} options.
   *
   * @param {string} name The metric name
   * @param {function} callback The callback for the CachedGauge
   * @param {Dimensions} dimensions The optional custom dimensions
   * @param {number} publishingIntervalInSeconds the optional publishing interval
   */
  validateCachedGaugeOptions: (name, callback, dimensions, publishingIntervalInSeconds) => {
    module.exports.validateCommonMetricParameters(name, dimensions, publishingIntervalInSeconds);
    // Should we validate the promise call back, it may be expensive or produce a race condition in some use-cases.
  },

  /**
   * Validates the create histogram Options.
   *
   * @param {string} name The metric name
   * @param {Dimensions} dimensions The optional custom dimensions
   * @param {number} publishingIntervalInSeconds the optional publishing interval
   */
  validateHistogramOptions: (name, dimensions, publishingIntervalInSeconds) => {
    module.exports.validateCommonMetricParameters(name, dimensions, publishingIntervalInSeconds);
  },

  /**
   * Validates the create counter Options.
   *
   * @param {string} name The metric name
   * @param {Dimensions} dimensions The optional custom dimensions
   * @param {number} publishingIntervalInSeconds the optional publishing interval
   */
  validateCounterOptions: (name, dimensions, publishingIntervalInSeconds) => {
    module.exports.validateCommonMetricParameters(name, dimensions, publishingIntervalInSeconds);
  },

  /**
   * Validates the create timer Options.
   *
   * @param {string} name The metric name
   * @param {Dimensions} dimensions The optional custom dimensions
   * @param {number} publishingIntervalInSeconds the optional publishing interval
   */
  validateTimerOptions: (name, dimensions, publishingIntervalInSeconds) => {
    module.exports.validateCommonMetricParameters(name, dimensions, publishingIntervalInSeconds);
  },

  /**
   * Validates the create timer Options.
   *
   * @param {string} name The metric name
   * @param {Metric} metric The metric instance
   * @param {Dimensions} dimensions The optional custom dimensions
   * @param {number} publishingIntervalInSeconds the optional publishing interval
   */
  validateRegisterOptions: (name, metric, dimensions, publishingIntervalInSeconds) => {
    module.exports.validateMetric(metric);
    module.exports.validateCommonMetricParameters(name, dimensions, publishingIntervalInSeconds);
  },

  /**
   * Validates the create settable gauge Options.
   *
   * @param {string} name The metric name
   * @param {Dimensions} dimensions The optional custom dimensions
   * @param {number} publishingIntervalInSeconds the optional publishing interval
   */
  validateSettableGaugeOptions: (name, dimensions, publishingIntervalInSeconds) => {
    module.exports.validateCommonMetricParameters(name, dimensions, publishingIntervalInSeconds);
  },

  /**
   * Validates the options that are common amoung all create metric methods
   *
   * @param {string} name The metric name
   * @param {Dimensions} dimensions The optional custom dimensions
   * @param {number} publishingIntervalInSeconds the optional publishing interval
   */
  validateCommonMetricParameters: (name, dimensions, publishingIntervalInSeconds) => {
    module.exports.validateMetricName(name);
    module.exports.validateOptionalDimensions(dimensions);
    module.exports.validateOptionalPublishingInterval(publishingIntervalInSeconds);
  },

  /**
   * Validates the metric name.
   *
   * @param name The metric name.
   */
  validateMetricName: name => {
    const type = typeof name;
    if (type !== 'string') {
      throw new TypeError(`options.name is a required option and must be of type string, actual type: ${type}`);
    }
  },

  /**
   * Validates that a metric implements the metric interface.
   *
   * @function
   * @name validateMetric
   * @param {Metric} metric The object that is supposed to be a metric.
   */
  validateMetric,

  /**
   * Validates the provided callback.
   *
   * @param callback The provided callback for a gauge.
   */
  validateNumberReturningCallback: callback => {
    const type = typeof callback;
    if (type !== 'function') {
      throw new TypeError(`options.callback is a required option and must be function, actual type: ${type}`);
    }

    const callbackType = typeof callback();
    if (callbackType !== 'number') {
      throw new TypeError(`options.callback must return a number, actual return type: ${callbackType}`);
    }
  },

  /**
   * Validates a set of optional dimensions
   * @param dimensionsOptional
   */
  validateOptionalDimensions: dimensionsOptional => {
    Optional.ofNullable(dimensionsOptional).ifPresent(dimensions => {
      const type = typeof dimensions;
      if (type !== 'object') {
        throw new TypeError(`options.dimensions should be an object, actual type: ${type}`);
      }

      if (Array.isArray(dimensions)) {
        throw new TypeError('dimensions where detected to be an array, expected Object<string, string>');
      }

      Object.keys(dimensions).forEach(key => {
        const valueType = typeof dimensions[key];
        if (valueType !== 'string') {
          throw new TypeError(`options.dimensions.${key} should be of type string, actual type: ${type}`);
        }
      });
    });
  },

  /**
   * Validates that an optional logger instance at least has the methods we expect.
   * @param loggerOptional
   */
  validateOptionalLogger: loggerOptional => {
    Optional.ofNullable(loggerOptional).ifPresent(logger => {
      if (
        typeof logger.debug !== 'function' ||
        typeof logger.info !== 'function' ||
        typeof logger.warn !== 'function' ||
        typeof logger.error !== 'function'
      ) {
        throw new TypeError(
          'The logger that was passed in does not support all required ' +
            'logging methods, expected object to have functions debug, info, warn, and error with ' +
            'method signatures (...msgs) => {}'
        );
      }
    });
  },

  /**
   * Validates the optional publishing interval.
   *
   * @param publishingIntervalInSecondsOptional The optional publishing interval.
   */
  validateOptionalPublishingInterval: publishingIntervalInSecondsOptional => {
    Optional.ofNullable(publishingIntervalInSecondsOptional).ifPresent(publishingIntervalInSeconds => {
      const type = typeof publishingIntervalInSeconds;
      if (type !== 'number') {
        throw new TypeError(`options.publishingIntervalInSeconds must be of type number, actual type: ${type}`);
      }
    });
  },

  /**
   * Validates optional params for a Reporter
   * @param {ReporterOptions} options The optional params
   */
  validateReporterParameters: options => {
    if (options) {
      module.exports.validateOptionalDimensions(options.defaultDimensions);
      module.exports.validateOptionalLogger(options.logger);

      const type = typeof options.unrefTimers;
      if (type !== 'boolean' && type !== 'undefined') {
        throw new TypeError(`options.unrefTimers should be a boolean or undefined, actua
Download .txt
gitextract_rxmrbihn/

├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── .jsdoc.json
├── .prettierrc
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── Readme.md
├── documentation/
│   ├── assets/
│   │   └── measured.license.md
│   └── docstrap_customized/
│       └── template/
│           └── publish.js
├── lerna.json
├── package.json
├── packages/
│   ├── measured-core/
│   │   ├── README.md
│   │   ├── lib/
│   │   │   ├── Collection.js
│   │   │   ├── index.js
│   │   │   ├── metrics/
│   │   │   │   ├── CachedGauge.js
│   │   │   │   ├── Counter.js
│   │   │   │   ├── Gauge.js
│   │   │   │   ├── Histogram.js
│   │   │   │   ├── Meter.js
│   │   │   │   ├── Metric.js
│   │   │   │   ├── NoOpMeter.js
│   │   │   │   ├── SettableGauge.js
│   │   │   │   └── Timer.js
│   │   │   ├── util/
│   │   │   │   ├── BinaryHeap.js
│   │   │   │   ├── ExponentiallyDecayingSample.js
│   │   │   │   ├── ExponentiallyMovingWeightedAverage.js
│   │   │   │   ├── Stopwatch.js
│   │   │   │   └── units.js
│   │   │   └── validators/
│   │   │       └── metricValidators.js
│   │   ├── package.json
│   │   └── test/
│   │       ├── common.js
│   │       ├── integration/
│   │       │   └── test-Collection_end.js
│   │       └── unit/
│   │           ├── metrics/
│   │           │   ├── test-CachedGauge.js
│   │           │   ├── test-Counter.js
│   │           │   ├── test-Gauge.js
│   │           │   ├── test-Histogram.js
│   │           │   ├── test-Meter.js
│   │           │   ├── test-NoOpMeter.js
│   │           │   ├── test-SettableGauge.js
│   │           │   └── test-Timer.js
│   │           ├── test-Collection.js
│   │           └── util/
│   │               ├── test-BinaryHeap.js
│   │               ├── test-ExponentiallyDecayingSample.js
│   │               ├── test-ExponentiallyMovingWeightedAverage.js
│   │               └── test-Stopwatch.js
│   ├── measured-node-metrics/
│   │   ├── README.md
│   │   ├── lib/
│   │   │   ├── index.js
│   │   │   ├── nodeHttpRequestMetrics.js
│   │   │   ├── nodeOsMetrics.js
│   │   │   ├── nodeProcessMetrics.js
│   │   │   └── utils/
│   │   │       └── CpuUtils.js
│   │   ├── package.json
│   │   └── test/
│   │       ├── integration/
│   │       │   ├── test-express-middleware.js
│   │       │   └── test-koa-middleware.js
│   │       └── unit/
│   │           ├── TestReporter.js
│   │           ├── test-nodeHttpRequestMetrics.js
│   │           ├── test-nodeOsMetrics.js
│   │           ├── test-nodeProcessMetrics.js
│   │           └── utils/
│   │               └── test-CpuUtils.js
│   ├── measured-reporting/
│   │   ├── README.md
│   │   ├── lib/
│   │   │   ├── @types/
│   │   │   │   └── types.js
│   │   │   ├── index.js
│   │   │   ├── registries/
│   │   │   │   ├── DimensionAwareMetricsRegistry.js
│   │   │   │   └── SelfReportingMetricsRegistry.js
│   │   │   ├── reporters/
│   │   │   │   ├── LoggingReporter.js
│   │   │   │   └── Reporter.js
│   │   │   └── validators/
│   │   │       └── inputValidators.js
│   │   ├── package.json
│   │   └── test/
│   │       └── unit/
│   │           ├── registries/
│   │           │   ├── test-DimensionAwareMetricsRegistry.js
│   │           │   └── test-SelfReportingMetricsRegistry.js
│   │           ├── reporters/
│   │           │   ├── test-LoggingReporter.js
│   │           │   └── test-Reporter.js
│   │           └── validators/
│   │               └── test-inputValidators.js
│   └── measured-signalfx-reporter/
│       ├── README.md
│       ├── lib/
│       │   ├── SignalFxEventCategories.js
│       │   ├── index.js
│       │   ├── registries/
│       │   │   └── SignalFxSelfReportingMetricsRegistry.js
│       │   ├── reporters/
│       │   │   └── SignalFxMetricsReporter.js
│       │   └── validators/
│       │       └── inputValidators.js
│       ├── package.json
│       └── test/
│           ├── unit/
│           │   ├── registries/
│           │   │   └── test-SignalFxSelfReportingMetricsRegistry.js
│           │   ├── reporters/
│           │   │   └── test-SignalFxMetricsReporter.js
│           │   └── validators/
│           │       └── test-inputValidators.js
│           └── user-acceptance-test/
│               └── index.js
├── scripts/
│   ├── generate-docs.sh
│   └── publish.sh
└── tutorials/
    ├── SignalFx Express Full End to End Example.md
    └── SignalFx Koa Full End to End Example.md
Download .txt
SYMBOL INDEX (229 symbols across 30 files)

FILE: documentation/docstrap_customized/template/publish.js
  function find (line 117) | function find(spec) {
  function tutoriallink (line 121) | function tutoriallink(tutorial) {
  function getAncestorLinks (line 129) | function getAncestorLinks(doclet) {
  function hashToLink (line 133) | function hashToLink(doclet, hash) {
  function needsSignature (line 144) | function needsSignature(doclet) {
  function addSignatureParams (line 165) | function addSignatureParams(f) {
  function addSignatureReturns (line 187) | function addSignatureReturns(f) {
  function addSignatureTypes (line 198) | function addSignatureTypes(f) {
  function addAttribs (line 204) | function addAttribs(f) {
  function shortenPaths (line 210) | function shortenPaths(files, commonPrefix) {
  function getPathFromDoclet (line 234) | function getPathFromDoclet(doclet) {
  function searchData (line 244) | function searchData(html) {
  function generate (line 262) | function generate(docType, title, docs, filename, resolveLinks) {
  function generateSourceFiles (line 289) | function generateSourceFiles(sourceFiles) {
  function attachModuleSymbols (line 321) | function attachModuleSymbols(doclets, modules) {
  function buildNav (line 365) | function buildNav(members) {
  function generateTutorial (line 846) | function generateTutorial(title, tutorial, filename) {
  function saveChildren (line 873) | function saveChildren(node) {
  function generateQuickTextSearch (line 880) | function generateQuickTextSearch(templatePath, searchableDocuments, navO...

FILE: packages/measured-core/lib/Collection.js
  class Collection (line 21) | class Collection {
    method constructor (line 26) | constructor(name) {
    method register (line 49) | register(name, metric) {
    method toJSON (line 57) | toJSON() {
    method gauge (line 82) | gauge(name, readFn) {
    method counter (line 104) | counter(name, properties) {
    method histogram (line 126) | histogram(name, properties) {
    method timer (line 148) | timer(name, properties) {
    method meter (line 170) | meter(name, properties) {
    method settableGauge (line 192) | settableGauge(name, properties) {
    method cachedGauge (line 216) | cachedGauge(name, valueProducingPromiseCallback, updateIntervalInSecon...
    method _getMetricForNameAndType (line 240) | _getMetricForNameAndType(name, requestedType) {
    method _validateName (line 260) | _validateName(name) {
    method end (line 269) | end() {

FILE: packages/measured-core/lib/metrics/CachedGauge.js
  class CachedGauge (line 26) | class CachedGauge {
    method constructor (line 34) | constructor(valueProducingPromiseCallback, updateIntervalInSeconds, ti...
    method _updateValue (line 49) | _updateValue() {
    method toJSON (line 58) | toJSON() {
    method getType (line 66) | getType() {
    method end (line 73) | end() {

FILE: packages/measured-core/lib/metrics/Counter.js
  class Counter (line 16) | class Counter {
    method constructor (line 20) | constructor(properties) {
    method toJSON (line 30) | toJSON() {
    method inc (line 38) | inc(n) {
    method dec (line 46) | dec(n) {
    method reset (line 54) | reset(count) {
    method getType (line 62) | getType() {

FILE: packages/measured-core/lib/metrics/Gauge.js
  class Gauge (line 12) | class Gauge {
    method constructor (line 16) | constructor(readFn) {
    method toJSON (line 23) | toJSON() {
    method getType (line 31) | getType() {

FILE: packages/measured-core/lib/metrics/Histogram.js
  constant EDS (line 3) | const EDS = require('../util/ExponentiallyDecayingSample');
  class Histogram (line 17) | class Histogram {
    method constructor (line 21) | constructor(properties) {
    method _initializeState (line 26) | _initializeState() {
    method update (line 44) | update(value) {
    method _percentiles (line 54) | _percentiles(percentiles) {
    method weightedPercentiles (line 83) | weightedPercentiles(percentiles) {
    method reset (line 129) | reset() {
    method hasValues (line 141) | hasValues() {
    method toJSON (line 148) | toJSON() {
    method _updateMin (line 167) | _updateMin(value) {
    method _updateMax (line 173) | _updateMax(value) {
    method _updateVariance (line 179) | _updateVariance(value) {
    method _calculateMean (line 199) | _calculateMean() {
    method _calculateVariance (line 207) | _calculateVariance() {
    method _calculateStddev (line 215) | _calculateStddev() {
    method getType (line 223) | getType() {

FILE: packages/measured-core/lib/metrics/Meter.js
  constant EWMA (line 3) | const EWMA = require('../util/ExponentiallyMovingWeightedAverage');
  constant RATE_UNIT (line 5) | const RATE_UNIT = units.SECONDS;
  constant TICK_INTERVAL (line 6) | const TICK_INTERVAL = 5 * units.SECONDS;
  class Meter (line 18) | class Meter {
    method constructor (line 22) | constructor(properties) {
    method _initializeState (line 35) | _initializeState() {
    method mark (line 56) | mark(n) {
    method start (line 70) | start() {}
    method end (line 72) | end() {
    method ref (line 80) | ref() {
    method unref (line 89) | unref() {
    method _tick (line 95) | _tick() {
    method reset (line 104) | reset() {
    method meanRate (line 109) | meanRate() {
    method currentRate (line 118) | currentRate() {
    method toJSON (line 133) | toJSON() {
    method _getTime (line 144) | _getTime() {
    method getType (line 157) | getType() {

FILE: packages/measured-core/lib/metrics/Metric.js
  class Metric (line 19) | class Metric {
    method toJSON (line 26) | toJSON() {}
    method getType (line 32) | getType() {}

FILE: packages/measured-core/lib/metrics/NoOpMeter.js
  class NoOpMeter (line 17) | class NoOpMeter {
    method mark (line 23) | mark(n) {}
    method start (line 28) | start() {}
    method end (line 33) | end() {}
    method ref (line 38) | ref() {}
    method unref (line 43) | unref() {}
    method reset (line 48) | reset() {}
    method meanRate (line 53) | meanRate() {}
    method currentRate (line 58) | currentRate() {}
    method toJSON (line 64) | toJSON() {
    method getType (line 72) | getType() {

FILE: packages/measured-core/lib/metrics/SettableGauge.js
  class SettableGauge (line 16) | class SettableGauge {
    method constructor (line 20) | constructor(options) {
    method setValue (line 25) | setValue(value) {
    method toJSON (line 32) | toJSON() {
    method getType (line 40) | getType() {

FILE: packages/measured-core/lib/metrics/Timer.js
  class Timer (line 36) | class Timer {
    method constructor (line 40) | constructor(properties) {
    method start (line 56) | start() {
    method update (line 71) | update(value) {
    method reset (line 79) | reset() {
    method end (line 84) | end() {
    method ref (line 91) | ref() {
    method unref (line 98) | unref() {
    method toJSON (line 110) | toJSON() {
    method getType (line 121) | getType() {

FILE: packages/measured-core/lib/util/BinaryHeap.js
  class BinaryHeap (line 5) | class BinaryHeap {
    method constructor (line 6) | constructor(options) {
    method add (line 17) | add(...elements) {
    method first (line 24) | first() {
    method removeFirst (line 28) | removeFirst() {
    method clone (line 40) | clone() {
    method toSortedArray (line 47) | toSortedArray() {
    method toArray (line 64) | toArray() {
    method size (line 68) | size() {
    method _bubble (line 72) | _bubble(bubbleIndex) {
    method _sink (line 94) | _sink(sinkIndex) {
    method _parentIndex (line 142) | _parentIndex(index) {
    method _childIndexes (line 146) | _childIndexes(index) {
    method _score (line 150) | _score(element) {

FILE: packages/measured-core/lib/util/ExponentiallyDecayingSample.js
  constant RESCALE_INTERVAL (line 4) | const RESCALE_INTERVAL = units.HOURS;
  constant ALPHA (line 5) | const ALPHA = 0.015;
  constant SIZE (line 6) | const SIZE = 1028;
  class ExponentiallyDecayingSample (line 11) | class ExponentiallyDecayingSample {
    method constructor (line 12) | constructor(options) {
    method update (line 27) | update(value, timestamp) {
    method toSortedArray (line 55) | toSortedArray() {
    method toArray (line 59) | toArray() {
    method toArrayWithWeights (line 63) | toArrayWithWeights() {
    method _weight (line 67) | _weight(age) {
    method _priority (line 73) | _priority(age) {
    method _random (line 77) | _random() {
    method _rescale (line 81) | _rescale(now) {

FILE: packages/measured-core/lib/util/ExponentiallyMovingWeightedAverage.js
  constant TICK_INTERVAL (line 3) | const TICK_INTERVAL = 5 * units.SECONDS;
  class ExponentiallyMovingWeightedAverage (line 8) | class ExponentiallyMovingWeightedAverage {
    method constructor (line 9) | constructor(timePeriod, tickInterval) {
    method update (line 17) | update(n) {
    method tick (line 21) | tick() {
    method rate (line 28) | rate(timeUnit) {

FILE: packages/measured-core/lib/util/Stopwatch.js
  class Stopwatch (line 8) | class Stopwatch extends EventEmitter {
    method constructor (line 13) | constructor(options) {
    method end (line 29) | end() {
    method _getTime (line 41) | _getTime() {

FILE: packages/measured-core/lib/util/units.js
  constant NANOSECONDS (line 1) | const NANOSECONDS = 1 / (1000 * 1000);
  constant MICROSECONDS (line 2) | const MICROSECONDS = 1 / 1000;
  constant MILLISECONDS (line 3) | const MILLISECONDS = 1;
  constant SECONDS (line 4) | const SECONDS = 1000 * MILLISECONDS;
  constant MINUTES (line 5) | const MINUTES = 60 * SECONDS;
  constant HOURS (line 6) | const HOURS = 60 * MINUTES;
  constant DAYS (line 7) | const DAYS = 24 * HOURS;

FILE: packages/measured-node-metrics/lib/nodeHttpRequestMetrics.js
  constant DEFAULT_REQUEST_METRICS_REPORTING_INTERVAL_IN_SECONDS (line 7) | const DEFAULT_REQUEST_METRICS_REPORTING_INTERVAL_IN_SECONDS = 10;

FILE: packages/measured-node-metrics/lib/nodeOsMetrics.js
  constant DEFAULT_NODE_OS_METRICS_REPORTING_INTERVAL_IN_SECONDS (line 10) | const DEFAULT_NODE_OS_METRICS_REPORTING_INTERVAL_IN_SECONDS = 30;

FILE: packages/measured-node-metrics/lib/nodeProcessMetrics.js
  constant DEFAULT_NODE_PROCESS_METRICS_REPORTING_INTERVAL_IN_SECONDS (line 9) | const DEFAULT_NODE_PROCESS_METRICS_REPORTING_INTERVAL_IN_SECONDS = 30;

FILE: packages/measured-node-metrics/test/unit/TestReporter.js
  class TestReporter (line 6) | class TestReporter extends Reporter {
    method constructor (line 7) | constructor(options) {
    method getReportedMetrics (line 13) | getReportedMetrics() {
    method _reportMetrics (line 17) | _reportMetrics(metrics) {

FILE: packages/measured-node-metrics/test/unit/test-nodeHttpRequestMetrics.js
  class MockResponse (line 9) | class MockResponse extends EventEmitter {
    method constructor (line 10) | constructor() {
    method finish (line 15) | finish() {

FILE: packages/measured-reporting/lib/registries/DimensionAwareMetricsRegistry.js
  class DimensionAwareMetricsRegistry (line 6) | class DimensionAwareMetricsRegistry {
    method constructor (line 10) | constructor(options) {
    method hasMetric (line 28) | hasMetric(name, dimensions) {
    method getMetric (line 40) | getMetric(name, dimensions) {
    method getMetricWrapperByKey (line 51) | getMetricWrapperByKey(key) {
    method putMetric (line 63) | putMetric(name, metric, dimensions) {
    method allKeys (line 77) | allKeys() {
    method _generateStorageKey (line 89) | _generateStorageKey(name, dimensions) {

FILE: packages/measured-reporting/lib/registries/SelfReportingMetricsRegistry.js
  function prefix (line 15) | function prefix() {
  class SelfReportingMetricsRegistry (line 22) | class SelfReportingMetricsRegistry {
    method constructor (line 27) | constructor(reporters, options) {
    method register (line 77) | register(name, metric, dimensions, publishingIntervalInSeconds) {
    method getOrCreateGauge (line 115) | getOrCreateGauge(name, callback, dimensions, publishingIntervalInSecon...
    method getOrCreateHistogram (line 136) | getOrCreateHistogram(name, dimensions, publishingIntervalInSeconds) {
    method getOrCreateMeter (line 159) | getOrCreateMeter(name, dimensions, publishingIntervalInSeconds) {
    method getOrCreateCounter (line 181) | getOrCreateCounter(name, dimensions, publishingIntervalInSeconds) {
    method getOrCreateTimer (line 204) | getOrCreateTimer(name, dimensions, publishingIntervalInSeconds) {
    method getOrCreateSettableGauge (line 227) | getOrCreateSettableGauge(name, dimensions, publishingIntervalInSeconds) {
    method getOrCreateCachedGauge (line 252) | getOrCreateCachedGauge(
    method shutdown (line 276) | shutdown() {

FILE: packages/measured-reporting/lib/reporters/LoggingReporter.js
  class LoggingReporter (line 12) | class LoggingReporter extends Reporter {
    method constructor (line 16) | constructor(options) {
    method _reportMetrics (line 27) | _reportMetrics(metrics) {

FILE: packages/measured-reporting/lib/reporters/Reporter.js
  constant DEFAULT_REPORTING_INTERVAL_IN_SECONDS (line 5) | const DEFAULT_REPORTING_INTERVAL_IN_SECONDS = 10;
  function prefix (line 7) | function prefix() {
  class Reporter (line 61) | class Reporter {
    method constructor (line 65) | constructor(options) {
    method setRegistry (line 132) | setRegistry(registry) {
    method reportMetricOnInterval (line 142) | reportMetricOnInterval(metricKey, intervalInSeconds) {
    method _createIntervalCallback (line 168) | _createIntervalCallback(intervalInSeconds) {
    method _reportMetricsWithInterval (line 188) | _reportMetricsWithInterval(interval) {
    method _reportMetrics (line 221) | _reportMetrics(metrics) {
    method _getDimensions (line 231) | _getDimensions(metric) {
    method shutdown (line 238) | shutdown() {

FILE: packages/measured-reporting/test/unit/registries/test-SelfReportingMetricsRegistry.js
  method reportMetricOnInterval (line 17) | reportMetricOnInterval() {}
  method setRegistry (line 18) | setRegistry() {}

FILE: packages/measured-reporting/test/unit/reporters/test-Reporter.js
  class TestReporter (line 12) | class TestReporter extends Reporter {
    method constructor (line 13) | constructor(options) {
    method getReportedMetrics (line 19) | getReportedMetrics() {
    method _reportMetrics (line 23) | _reportMetrics(metrics) {
  class BadImpl (line 54) | class BadImpl extends Reporter {}
  method _reportMetrics (line 120) | _reportMetrics(metrics) {

FILE: packages/measured-signalfx-reporter/lib/registries/SignalFxSelfReportingMetricsRegistry.js
  class SignalFxSelfReportingMetricsRegistry (line 12) | class SignalFxSelfReportingMetricsRegistry extends SelfReportingMetricsR...
    method getOrCreateTimer (line 21) | getOrCreateTimer(name, dimensions, publishingIntervalInSeconds) {
    method getOrCreateMeter (line 46) | getOrCreateMeter(name, dimensions, publishingIntervalInSeconds) {
    method sendEvent (line 72) | sendEvent(eventType, category, dimensions, properties, timestamp) {

FILE: packages/measured-signalfx-reporter/lib/reporters/SignalFxMetricsReporter.js
  class SignalFxMetricsReporter (line 10) | class SignalFxMetricsReporter extends Reporter {
    method constructor (line 15) | constructor(signalFxClient, options) {
    method _reportMetrics (line 29) | _reportMetrics(metrics) {
    method _processMetric (line 57) | _processMetric(metric, currentBuiltRequest) {
    method _getValuesToProcessForType (line 92) | _getValuesToProcessForType(name, metric) {
    method _getValuesToProcessForTimer (line 123) | _getValuesToProcessForTimer(name, timer) {
    method _getValuesToProcessForGauge (line 138) | _getValuesToProcessForGauge(name, gauge) {
    method _getValuesToProcessForCounter (line 156) | _getValuesToProcessForCounter(name, counter) {
    method _getValuesToProcessForHistogram (line 174) | _getValuesToProcessForHistogram(name, histogram) {
    method sendEvent (line 230) | sendEvent(eventType, category, dimensions, properties, timestamp) {
  constant SIGNAL_FX_GAUGE (line 244) | const SIGNAL_FX_GAUGE = 'gauges';
  constant SIGNAL_FX_CUMULATIVE_COUNTER (line 245) | const SIGNAL_FX_CUMULATIVE_COUNTER = 'cumulative_counters';

FILE: packages/measured-signalfx-reporter/test/unit/registries/test-SignalFxSelfReportingMetricsRegistry.js
  class TestReporter (line 10) | class TestReporter extends Reporter {
    method reportMetricOnInterval (line 11) | reportMetricOnInterval(metricKey, intervalInSeconds) {}
    method _reportMetrics (line 12) | _reportMetrics(metrics) {}
Condensed preview — 90 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (272K chars).
[
  {
    "path": ".eslintignore",
    "chars": 13,
    "preview": "node_modules/"
  },
  {
    "path": ".eslintrc.json",
    "chars": 666,
    "preview": "{\n  \"extends\": \"airbnb/base\",\n  \"env\": {\n    \"jest\": true\n  },\n  \"rules\": {\n    \"max-len\": 0,\n    \"no-underscore-dangle\""
  },
  {
    "path": ".gitignore",
    "chars": 1023,
    "preview": "# Created by .ignore support plugin (hsz.mobi)\n### Node template\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-e"
  },
  {
    "path": ".jsdoc.json",
    "chars": 1215,
    "preview": "{\n  \"tags\": {\n    \"allowUnknownTags\": true\n  },\n  \"plugins\": [\"plugins/markdown\"],\n  \"templates\": {\n    \"logoFile\": \"img"
  },
  {
    "path": ".prettierrc",
    "chars": 77,
    "preview": "printWidth: 120\ntabWidth: 2\nsemi: true\nsingleQuote: true\nbracketSpacing: true"
  },
  {
    "path": ".travis.yml",
    "chars": 1029,
    "preview": "language: node_js\nnode_js:\n- 11\n- 10\n- 8\nbefore_install:\n- sudo apt-get -qq update\n- sudo apt-get install -y gawk jq\njob"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 3269,
    "preview": "# Contributing\n\nPull requests are welcome, please keep conversations and commit messages civil.\n\n1. Fork, then clone the"
  },
  {
    "path": "LICENSE",
    "chars": 1149,
    "preview": "MIT License\n\nCopyright (c) 2018 Yet Another Org and Contributors\nCopyright (c) 2012-2017 Felix Geisendörfer and Contribu"
  },
  {
    "path": "Readme.md",
    "chars": 2659,
    "preview": "# Measured\n\nNode libraries for measuring and reporting application-level metrics.\n\nMeasured is heavily inspired by Coda "
  },
  {
    "path": "documentation/assets/measured.license.md",
    "chars": 241,
    "preview": "measured.png and measured.svg by [SimpleIcon](http://www.simpleicon.com/) available at [flaticon](http://www.flaticon.co"
  },
  {
    "path": "documentation/docstrap_customized/template/publish.js",
    "chars": 25547,
    "preview": "\"use strict\";\n\n/**\n * @module template/publish\n * @type {*}\n */\n/*global env: true */\n\nvar template = require('jsdoc/tem"
  },
  {
    "path": "lerna.json",
    "chars": 132,
    "preview": "{\n  \"lerna\": \"2.11.0\",\n  \"npmClient\": \"yarn\",\n  \"useWorkspaces\": true,\n  \"packages\": [\n    \"packages/*\"\n  ],\n  \"version\""
  },
  {
    "path": "package.json",
    "chars": 1623,
    "preview": "{\n  \"private\": true,\n  \"devDependencies\": {\n    \"coveralls\": \"^3.0.1\",\n    \"eslint\": \"^4.19.1\",\n    \"eslint-config-airbn"
  },
  {
    "path": "packages/measured-core/README.md",
    "chars": 3384,
    "preview": "# Measured Core\n\nThe core measured library that has the Metric interfaces and implementations.\n\n[![npm](https://img.shie"
  },
  {
    "path": "packages/measured-core/lib/Collection.js",
    "chars": 7818,
    "preview": "const Optional = require('optional-js');\nconst Counter = require('./metrics/Counter');\nconst Gauge = require('./metrics/"
  },
  {
    "path": "packages/measured-core/lib/index.js",
    "chars": 2671,
    "preview": "const Collection = require('./Collection');\nconst Counter = require('./metrics/Counter');\nconst Gauge = require('./metri"
  },
  {
    "path": "packages/measured-core/lib/metrics/CachedGauge.js",
    "chars": 2389,
    "preview": "const { MetricTypes } = require('./Metric');\nconst TimeUnits = require('../util/units');\n\n/**\n * A Cached Gauge takes a "
  },
  {
    "path": "packages/measured-core/lib/metrics/Counter.js",
    "chars": 1786,
    "preview": "const { MetricTypes } = require('./Metric');\n\n/**\n * Counters are things that increment or decrement\n * @implements {Met"
  },
  {
    "path": "packages/measured-core/lib/metrics/Gauge.js",
    "chars": 779,
    "preview": "const { MetricTypes } = require('./Metric');\n\n/**\n * Values that can be read instantly\n * @implements {Metric}\n * @examp"
  },
  {
    "path": "packages/measured-core/lib/metrics/Histogram.js",
    "chars": 7002,
    "preview": "const { MetricTypes } = require('./Metric');\nconst binarySearch = require('binary-search');\nconst EDS = require('../util"
  },
  {
    "path": "packages/measured-core/lib/metrics/Meter.js",
    "chars": 4901,
    "preview": "const { MetricTypes } = require('./Metric');\nconst units = require('../util/units');\nconst EWMA = require('../util/Expon"
  },
  {
    "path": "packages/measured-core/lib/metrics/Metric.js",
    "chars": 2153,
    "preview": "/**\n * Interface for Metric types.\n *\n * Implementations\n * <p>\n * <li><a href=\"Counter.html\">Counter</a>, things that i"
  },
  {
    "path": "packages/measured-core/lib/metrics/NoOpMeter.js",
    "chars": 1269,
    "preview": "const { MetricTypes } = require('./Metric');\n\n/**\n * A No-Op Impl of Meter that can be used with a timer, to only create"
  },
  {
    "path": "packages/measured-core/lib/metrics/SettableGauge.js",
    "chars": 1538,
    "preview": "const { MetricTypes } = require('./Metric');\n\n/**\n * Works like a {@link Gauge}, but rather than getting its value from "
  },
  {
    "path": "packages/measured-core/lib/metrics/Timer.js",
    "chars": 3472,
    "preview": "const { MetricTypes } = require('./Metric');\nconst Histogram = require('./Histogram');\nconst Meter = require('./Meter');"
  },
  {
    "path": "packages/measured-core/lib/util/BinaryHeap.js",
    "chars": 3227,
    "preview": "/**\n * Based on http://en.wikipedia.org/wiki/Binary_Heap\n * as well as http://eloquentjavascript.net/appendix2.html\n */\n"
  },
  {
    "path": "packages/measured-core/lib/util/ExponentiallyDecayingSample.js",
    "chars": 2260,
    "preview": "const BinaryHeap = require('./BinaryHeap');\nconst units = require('./units');\n\nconst RESCALE_INTERVAL = units.HOURS;\ncon"
  },
  {
    "path": "packages/measured-core/lib/util/ExponentiallyMovingWeightedAverage.js",
    "chars": 750,
    "preview": "const units = require('./units');\n\nconst TICK_INTERVAL = 5 * units.SECONDS;\n\n/**\n * ExponentiallyMovingWeightedAverage\n "
  },
  {
    "path": "packages/measured-core/lib/util/Stopwatch.js",
    "chars": 1233,
    "preview": "const { EventEmitter } = require('events');\n\n/**\n * A simple object for tracking elapsed time\n *\n * @extends {EventEmitt"
  },
  {
    "path": "packages/measured-core/lib/util/units.js",
    "chars": 1016,
    "preview": "const NANOSECONDS = 1 / (1000 * 1000);\nconst MICROSECONDS = 1 / 1000;\nconst MILLISECONDS = 1;\nconst SECONDS = 1000 * MIL"
  },
  {
    "path": "packages/measured-core/lib/validators/metricValidators.js",
    "chars": 1293,
    "preview": "const { MetricTypes } = require('../metrics/Metric');\n\n// TODO: Object.values(...) does not exist in Node.js 6.x, switch"
  },
  {
    "path": "packages/measured-core/package.json",
    "chars": 1078,
    "preview": "{\n  \"name\": \"measured-core\",\n  \"description\": \"A Node library for measuring and reporting application-level metrics.\",\n "
  },
  {
    "path": "packages/measured-core/test/common.js",
    "chars": 281,
    "preview": "'use strict';\n\n/*\nvar common = exports;\nvar path   = require('path');\n\ncommon.dir      = {};\ncommon.dir.root = path.dirn"
  },
  {
    "path": "packages/measured-core/test/integration/test-Collection_end.js",
    "chars": 209,
    "preview": "'use strict';\n\nvar common = require('../common');\n\nvar collection = new common.measured.Collection();\n\ncollection.timer("
  },
  {
    "path": "packages/measured-core/test/unit/metrics/test-CachedGauge.js",
    "chars": 1406,
    "preview": "/*global describe, it, beforeEach, afterEach*/\nconst TimeUnits = require('../../../lib/util/units');\nconst CachedGauge ="
  },
  {
    "path": "packages/measured-core/test/unit/metrics/test-Counter.js",
    "chars": 1756,
    "preview": "/*global describe, it, beforeEach, afterEach*/\n'use strict';\n\nvar common = require('../../common');\nvar assert = require"
  },
  {
    "path": "packages/measured-core/test/unit/metrics/test-Gauge.js",
    "chars": 541,
    "preview": "/*global describe, it, beforeEach, afterEach*/\n'use strict';\n\nvar common = require('../../common');\nvar assert = require"
  },
  {
    "path": "packages/measured-core/test/unit/metrics/test-Histogram.js",
    "chars": 6203,
    "preview": "/*global describe, it, beforeEach, afterEach*/\n'use strict';\n\nvar common = require('../../common');\nvar assert = require"
  },
  {
    "path": "packages/measured-core/test/unit/metrics/test-Meter.js",
    "chars": 3356,
    "preview": "/*global describe, it, beforeEach, afterEach*/\n'use strict';\n\nvar common = require('../../common');\nvar assert = require"
  },
  {
    "path": "packages/measured-core/test/unit/metrics/test-NoOpMeter.js",
    "chars": 425,
    "preview": "/*global describe, it, beforeEach, afterEach*/\n\nvar common = require('../../common');\nvar assert = require('assert');\n\nd"
  },
  {
    "path": "packages/measured-core/test/unit/metrics/test-SettableGauge.js",
    "chars": 759,
    "preview": "/*global describe, it, beforeEach, afterEach*/\n'use strict';\n\nvar common = require('../../common');\nvar assert = require"
  },
  {
    "path": "packages/measured-core/test/unit/metrics/test-Timer.js",
    "chars": 1954,
    "preview": "/*global describe, it, beforeEach, afterEach*/\n'use strict';\n\nvar common = require('../../common');\nvar assert = require"
  },
  {
    "path": "packages/measured-core/test/unit/test-Collection.js",
    "chars": 959,
    "preview": "/*global describe, it, beforeEach, afterEach*/\n'use strict';\n\nvar common = require('../common');\nvar assert = require('a"
  },
  {
    "path": "packages/measured-core/test/unit/util/test-BinaryHeap.js",
    "chars": 3485,
    "preview": "/*global describe, it, beforeEach, afterEach*/\n'use strict';\n\nvar common = require('../../common');\nvar assert = require"
  },
  {
    "path": "packages/measured-core/test/unit/util/test-ExponentiallyDecayingSample.js",
    "chars": 3175,
    "preview": "/*global describe, it, beforeEach, afterEach*/\n'use strict';\n\nvar common = require('../../common');\nvar assert = require"
  },
  {
    "path": "packages/measured-core/test/unit/util/test-ExponentiallyMovingWeightedAverage.js",
    "chars": 905,
    "preview": "/*global describe, it, beforeEach, afterEach*/\n'use strict';\n\nvar common = require('../../common');\nvar assert = require"
  },
  {
    "path": "packages/measured-core/test/unit/util/test-Stopwatch.js",
    "chars": 1149,
    "preview": "/*global describe, it, beforeEach, afterEach*/\n'use strict';\n\nvar common = require('../../common');\nvar assert = require"
  },
  {
    "path": "packages/measured-node-metrics/README.md",
    "chars": 2339,
    "preview": "# Measured Node Metrics\n\nVarious metrics generators and http framework middlewares that can be used with a self reportin"
  },
  {
    "path": "packages/measured-node-metrics/lib/index.js",
    "chars": 4023,
    "preview": "const { nodeProcessMetrics, createProcessMetrics } = require('./nodeProcessMetrics');\nconst { nodeOsMetrics, createOSMet"
  },
  {
    "path": "packages/measured-node-metrics/lib/nodeHttpRequestMetrics.js",
    "chars": 4104,
    "preview": "const { Stopwatch } = require('measured-core');\n\n/**\n * The default reporting interval for requests\n * @type {number}\n *"
  },
  {
    "path": "packages/measured-node-metrics/lib/nodeOsMetrics.js",
    "chars": 3646,
    "preview": "const { Gauge, CachedGauge } = require('measured-core');\nconst { cpuAverage, calculateCpuUsagePercent } = require('./uti"
  },
  {
    "path": "packages/measured-node-metrics/lib/nodeProcessMetrics.js",
    "chars": 3111,
    "preview": "const { Gauge } = require('measured-core');\nconst process = require('process');\n\n/**\n * The default reporting interval f"
  },
  {
    "path": "packages/measured-node-metrics/lib/utils/CpuUtils.js",
    "chars": 1197,
    "preview": "const os = require('os');\n\n/**\n * @module CpuUtils\n */\nmodule.exports = {\n  /**\n   *\n   * @return {{idle: number, total:"
  },
  {
    "path": "packages/measured-node-metrics/package.json",
    "chars": 1196,
    "preview": "{\n  \"name\": \"measured-node-metrics\",\n  \"description\": \"Various metrics generators and http framework middlewares that ca"
  },
  {
    "path": "packages/measured-node-metrics/test/integration/test-express-middleware.js",
    "chars": 3675,
    "preview": "/*global describe, it, beforeEach, afterEach*/\nconst express = require('express');\nconst Registry = require('measured-re"
  },
  {
    "path": "packages/measured-node-metrics/test/integration/test-koa-middleware.js",
    "chars": 4001,
    "preview": "const Koa = require('koa');\nconst KoaBodyParser = require('koa-bodyparser');\nconst Router = require('koa-router');\nconst"
  },
  {
    "path": "packages/measured-node-metrics/test/unit/TestReporter.js",
    "chars": 374,
    "preview": "const { Reporter } = require('measured-reporting');\n\n/**\n * @extends Reporter\n */\nclass TestReporter extends Reporter {\n"
  },
  {
    "path": "packages/measured-node-metrics/test/unit/test-nodeHttpRequestMetrics.js",
    "chars": 3038,
    "preview": "/*global describe, it, beforeEach, afterEach*/\nconst assert = require('assert');\nconst EventEmitter = require('events');"
  },
  {
    "path": "packages/measured-node-metrics/test/unit/test-nodeOsMetrics.js",
    "chars": 1716,
    "preview": "/*global describe, it, beforeEach, afterEach*/\nconst assert = require('assert');\nconst { validateMetric } = require('mea"
  },
  {
    "path": "packages/measured-node-metrics/test/unit/test-nodeProcessMetrics.js",
    "chars": 1706,
    "preview": "/*global describe, it, beforeEach, afterEach*/\nconst assert = require('assert');\nconst { validateMetric } = require('mea"
  },
  {
    "path": "packages/measured-node-metrics/test/unit/utils/test-CpuUtils.js",
    "chars": 793,
    "preview": "/*global describe, it, beforeEach, afterEach*/\nconst assert = require('assert');\nconst CpuUtils = require('../../../lib/"
  },
  {
    "path": "packages/measured-reporting/README.md",
    "chars": 4970,
    "preview": "# Measured Reporting\n\nThe registry and reporting library that has the classes needed to create a dimension aware, self r"
  },
  {
    "path": "packages/measured-reporting/lib/@types/types.js",
    "chars": 608,
    "preview": "/**\n * A wrapper object around a {@link Metric}, {@link Dimensions} and the metric name\n *\n * @interface MetricWrapper\n "
  },
  {
    "path": "packages/measured-reporting/lib/index.js",
    "chars": 935,
    "preview": "const SelfReportingMetricsRegistry = require('./registries/SelfReportingMetricsRegistry');\nconst Reporter = require('./r"
  },
  {
    "path": "packages/measured-reporting/lib/registries/DimensionAwareMetricsRegistry.js",
    "chars": 3493,
    "preview": "const mapcap = require('mapcap');\n\n/**\n * Simple registry that stores Metrics by name and dimensions.\n */\nclass Dimensio"
  },
  {
    "path": "packages/measured-reporting/lib/registries/SelfReportingMetricsRegistry.js",
    "chars": 11137,
    "preview": "const consoleLogLevel = require('console-log-level');\nconst { CachedGauge, SettableGauge, Gauge, Timer, Counter, Meter, "
  },
  {
    "path": "packages/measured-reporting/lib/reporters/LoggingReporter.js",
    "chars": 1791,
    "preview": "const Reporter = require('./Reporter');\n\n/**\n * A reporter impl that simply logs the metrics via the Logger.\n *\n * @exam"
  },
  {
    "path": "packages/measured-reporting/lib/reporters/Reporter.js",
    "chars": 8413,
    "preview": "const consoleLogLevel = require('console-log-level');\nconst Optional = require('optional-js');\nconst { validateReporterP"
  },
  {
    "path": "packages/measured-reporting/lib/validators/inputValidators.js",
    "chars": 9103,
    "preview": "const Optional = require('optional-js');\nconst { validateMetric } = require('measured-core').metricValidators;\n\n/**\n * T"
  },
  {
    "path": "packages/measured-reporting/package.json",
    "chars": 1158,
    "preview": "{\n  \"name\": \"measured-reporting\",\n  \"description\": \"The classes needed to create self reporting dimension aware metrics "
  },
  {
    "path": "packages/measured-reporting/test/unit/registries/test-DimensionAwareMetricsRegistry.js",
    "chars": 4012,
    "preview": "/*global describe, it, beforeEach, afterEach*/\nconst assert = require('assert');\nconst { Counter } = require('measured-c"
  },
  {
    "path": "packages/measured-reporting/test/unit/registries/test-SelfReportingMetricsRegistry.js",
    "chars": 5012,
    "preview": "/*global describe, it, beforeEach, afterEach*/\nconst assert = require('assert');\nconst sinon = require('sinon');\nconst {"
  },
  {
    "path": "packages/measured-reporting/test/unit/reporters/test-LoggingReporter.js",
    "chars": 1518,
    "preview": "/*global describe, it, beforeEach, afterEach*/\nconst assert = require('assert');\nconst { LoggingReporter } = require('.."
  },
  {
    "path": "packages/measured-reporting/test/unit/reporters/test-Reporter.js",
    "chars": 5292,
    "preview": "/*global describe, it, beforeEach, afterEach*/\nconst assert = require('assert');\nconst TimeUnits = require('measured-cor"
  },
  {
    "path": "packages/measured-reporting/test/unit/validators/test-inputValidators.js",
    "chars": 5794,
    "preview": "/*global describe, it, beforeEach, afterEach*/\nconst consoleLogLevel = require('console-log-level');\nconst loglevel = re"
  },
  {
    "path": "packages/measured-signalfx-reporter/README.md",
    "chars": 1736,
    "preview": "# Measured SignalFx Reporter\n\nThis package ties together [measured-core](../measured-core) and [measured-reporting](../m"
  },
  {
    "path": "packages/measured-signalfx-reporter/lib/SignalFxEventCategories.js",
    "chars": 1356,
    "preview": "/**\n * Different categories of events supported, within the SignalFx Event API.\n *\n * @example\n * const registry = new S"
  },
  {
    "path": "packages/measured-signalfx-reporter/lib/index.js",
    "chars": 678,
    "preview": "const SignalFxMetricsReporter = require('./reporters/SignalFxMetricsReporter');\nconst SignalFxSelfReportingMetricsRegist"
  },
  {
    "path": "packages/measured-signalfx-reporter/lib/registries/SignalFxSelfReportingMetricsRegistry.js",
    "chars": 3647,
    "preview": "const { NoOpMeter, Timer } = require('measured-core');\nconst { SelfReportingMetricsRegistry } = require('measured-report"
  },
  {
    "path": "packages/measured-signalfx-reporter/lib/reporters/SignalFxMetricsReporter.js",
    "chars": 9422,
    "preview": "const { Reporter } = require('measured-reporting');\nconst { MetricTypes } = require('measured-core');\nconst { validateSi"
  },
  {
    "path": "packages/measured-signalfx-reporter/lib/validators/inputValidators.js",
    "chars": 596,
    "preview": "/**\n * Validation functions for validating public input\n * @module SignalFxReporterInputValidators\n * @private\n */\nmodul"
  },
  {
    "path": "packages/measured-signalfx-reporter/package.json",
    "chars": 1241,
    "preview": "{\n  \"name\": \"measured-signalfx-reporter\",\n  \"description\": \"A Registry Reporter that knows how to report core metrics to"
  },
  {
    "path": "packages/measured-signalfx-reporter/test/unit/registries/test-SignalFxSelfReportingMetricsRegistry.js",
    "chars": 1250,
    "preview": "/*global describe, it, beforeEach, afterEach*/\nconst { SignalFxSelfReportingMetricsRegistry } = require('../../../lib');"
  },
  {
    "path": "packages/measured-signalfx-reporter/test/unit/reporters/test-SignalFxMetricsReporter.js",
    "chars": 6475,
    "preview": "/*global describe, it, beforeEach, afterEach*/\nconst { SignalFxMetricsReporter } = require('../../../lib');\nconst { Hist"
  },
  {
    "path": "packages/measured-signalfx-reporter/test/unit/validators/test-inputValidators.js",
    "chars": 543,
    "preview": "/*global describe, it, beforeEach, afterEach*/\nconst { validateSignalFxClient } = require('../../../lib/validators/input"
  },
  {
    "path": "packages/measured-signalfx-reporter/test/user-acceptance-test/index.js",
    "chars": 2553,
    "preview": "const signalfx = require('signalfx');\nconst express = require('express');\nconst consoleLogLevel = require('console-log-l"
  },
  {
    "path": "scripts/generate-docs.sh",
    "chars": 2363,
    "preview": "#!/bin/bash\n\nSCRIPT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nROOT_DIR=\"${SCRIPT_DIR}/..\"\nDOCSTRAP_PATH=\"$"
  },
  {
    "path": "scripts/publish.sh",
    "chars": 3327,
    "preview": "#!/bin/bash\n\n######################################################################\n#\n# This script is intended to be us"
  },
  {
    "path": "tutorials/SignalFx Express Full End to End Example.md",
    "chars": 3067,
    "preview": "### Using Measured to instrument OS, Process and Express Metrics.\n\nThis tutorial shows how to use the measured libraries"
  },
  {
    "path": "tutorials/SignalFx Koa Full End to End Example.md",
    "chars": 3204,
    "preview": "### Using Measured to instrument OS, Process and Koa Metrics.\n\nThis tutorial shows how to use the measured libraries to "
  }
]

About this extraction

This page contains the full source code of the felixge/node-measured GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 90 files (248.9 KB), approximately 65.5k tokens, and a symbol index with 229 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!