Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,27 @@ Used to record a value which can vary over time, like temperature.
metrics.gauge('greenhouse_temperature', temp [, labelObject ]);
```

#### Using a gauge to track the "in-flight count" for functions and promises

Using the `.run()` and `.resolve()` methods, we can keep an instantaneous gauge of how many such functions/promises
are currently running / waiting to resolve/reject:

```
const delayMS = 1000;

const func = async () => {
await new Promise(resolve => setTimeout(resolve, delayMS));
};

const promise = new Promise(resolve => setTimeout(resolve, delayMS));

// this gauge will have a value incremented by 1 when func begins, and decremened by 1 when func ends
metrics.run('func_in_flight', func);

// this gauge will have a value incremented by 1 when first called, and decremened by 1 when the promise resolves/rejects
metrics.resolve('promise_in_flight', promise);
```

#### Counter

Used to record increases to a monotonic counter, like requests served.
Expand Down
15 changes: 15 additions & 0 deletions src/metrics-gatherer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,21 @@ export class MetricsGatherer {
}
}

// increment/decrement a gauge during the runtime of a function
public async run(name: string, func: () => any, labels: LabelSet = {}) {
this.inc(name, 1, labels);
await func();
this.inc(name, -1, labels);
Comment on lines +118 to +119
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Matching the other function this should be

Suggested change
await func();
this.inc(name, -1, labels);
try {
await func();
} finally {
this.inc(name, -1, labels);
}

and make sure we don't drop decrements

}

// increment/decrement a gauge during the runtime of a promise (wait for it to resolve)
public resolve(name: string, promise: Promise<any>, labels: LabelSet = {}) {
this.inc(name, 1, labels);
promise.finally(() => {
this.inc(name, -1, labels);
});
Comment on lines +125 to +127
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is better as

Suggested change
promise.finally(() => {
this.inc(name, -1, labels);
});
try {
await promise
} finally {
this.inc(name, -1, labels);
}

because it should also handle promises that don't support .finally

}

// decrement a gauge
public dec(name: string, val: number = 1, labels: LabelSet = {}) {
try {
Expand Down
28 changes: 28 additions & 0 deletions test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,34 @@ describe('Gauge', () => {
output = metrics.output();
expect(/undescribed_gauge 1/.test(output)).to.be.true;
});

it('should track runtime of functions properly', () => {
let output: string;

const func = async () => {
await new Promise(resolve => setTimeout(resolve, 100));
};
metrics.run('func_running_gauge', func);
output = metrics.output();
expect(/func_running_gauge 1/.test(output)).to.be.true;
setTimeout(() => {
output = metrics.output();
expect(/func_running_gauge 0/.test(output)).to.be.true;
}, 200);
});

it('should track runtime of promises properly', () => {
let output: string;

const promise = new Promise(resolve => setTimeout(resolve, 100));
metrics.resolve('promise_running_gauge', promise);
output = metrics.output();
expect(/promise_running_gauge 1/.test(output)).to.be.true;
setTimeout(() => {
output = metrics.output();
expect(/promise_running_gauge 0/.test(output)).to.be.true;
}, 200);
Comment on lines +70 to +73
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you change this to

Suggested change
setTimeout(() => {
output = metrics.output();
expect(/promise_running_gauge 0/.test(output)).to.be.true;
}, 200);
await Bluebird.delay(200);
output = metrics.output();
expect(/promise_running_gauge 0/.test(output)).to.be.true;

as it's clearer and also will mean that if the expect(/promise_running_gauge 0/.test(output)).to.be.true fails then it will be handled properly. The same goes for other setTimeouts

});
});

describe('Counter', () => {
Expand Down