feat: 초기 프로젝트 설정 및 룰.md 파일 추가

This commit is contained in:
2025-07-28 09:53:31 +09:00
commit 09a4d38512
8165 changed files with 1021855 additions and 0 deletions

146
api.hyungi.net/node_modules/tx2/API.md generated vendored Normal file
View File

@@ -0,0 +1,146 @@
## Classes
<dl>
<dt><a href="#TX2">TX2</a></dt>
<dd></dd>
</dl>
## Typedefs
<dl>
<dt><a href="#Metric">Metric</a> : <code>Object</code></dt>
<dd></dd>
<dt><a href="#Counter">Counter</a> : <code>object</code></dt>
<dd><p>Expose a metric of type: Counter.</p>
</dd>
</dl>
<a name="TX2"></a>
## TX2
**Kind**: global class
* [TX2](#TX2)
* [.action(action_name, [opts], fn)](#TX2.action)
* [.event(name, data)](#TX2.event)
* [.issue(err)](#TX2.issue)
* [.metric(name, [function])](#TX2.metric) ⇒ [<code>Metric</code>](#Metric)
* [.counter(name)](#TX2.counter) ⇒ [<code>Counter</code>](#Counter)
<a name="TX2.action"></a>
### TX2.action(action_name, [opts], fn)
Expose an action/function triggerable via PM2 or PM2.io
**Kind**: static method of [<code>TX2</code>](#TX2)
| Param | Type | Description |
| --- | --- | --- |
| action_name | <code>string</code> | Name of the action |
| [opts] | <code>object</code> | Optional parameter |
| fn | <code>function</code> | Function to be called |
**Example** *(Action without arguments)*
```js
tx2.action('run_query', (cb) => {
cb({ success: true })
})
```
**Example** *(Action with arguments)*
```js
tx2.action('run_query', arg1, (cb) => {
cb({ success: arg1 })
})
```
<a name="TX2.event"></a>
### TX2.event(name, data)
Sends an Event
**Kind**: static method of [<code>TX2</code>](#TX2)
| Param | Type | Description |
| --- | --- | --- |
| name | <code>string</code> | Name of the event |
| data | <code>object</code> | Metadata attached to the event |
**Example**
```js
tx2.event('event-name', { multi: 'data' })
```
<a name="TX2.issue"></a>
### TX2.issue(err)
Sends an Issue
**Kind**: static method of [<code>TX2</code>](#TX2)
| Param | Type | Description |
| --- | --- | --- |
| err | <code>string</code> \| <code>Error</code> | Error object or string to notify |
**Example**
```js
tx2.issue(new Error('bad error')
```
<a name="TX2.metric"></a>
### TX2.metric(name, [function]) ⇒ [<code>Metric</code>](#Metric)
Expose a Metric
**Kind**: static method of [<code>TX2</code>](#TX2)
**Returns**: [<code>Metric</code>](#Metric) - A metrics object
| Param | Type | Description |
| --- | --- | --- |
| name | <code>string</code> | Name of the metric |
| [function] | <code>function</code> | Optional function to trigger every second to retrieve updated value |
**Example**
```js
tx2.metric('metric_name', () => obj.value)
```
**Example**
```js
tx2.metric('metric_name', 'unit', () => obj.value)
```
**Example**
```js
let mn = tx2.metric('metric_name')
mn.set(20)
```
<a name="TX2.counter"></a>
### TX2.counter(name) ⇒ [<code>Counter</code>](#Counter)
Expose a Metric of type: Counter. By calling .inc() or .dec() you update that value
**Kind**: static method of [<code>TX2</code>](#TX2)
| Param | Type | Description |
| --- | --- | --- |
| name | <code>string</code> | Name of the Metric |
<a name="Metric"></a>
## Metric : <code>Object</code>
**Kind**: global typedef
**Properties**
| Name | Type | Description |
| --- | --- | --- |
| val | <code>function</code> | Return the current value |
| set | <code>function</code> | Set value |
<a name="Counter"></a>
## Counter : <code>object</code>
Expose a metric of type: Counter.
**Kind**: global typedef
**Properties**
| Name | Type | Description |
| --- | --- | --- |
| inc | <code>function</code> | Increment value |
| dev | <code>function</code> | Decrement value |

21
api.hyungi.net/node_modules/tx2/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2077 PM2
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.

44
api.hyungi.net/node_modules/tx2/README.md generated vendored Normal file
View File

@@ -0,0 +1,44 @@
## tx2
Report Events, Metrics, Issues, Actions to PM2 and PM2.io.
```javascript
const tx2 = require('tx2')
let body = { calories : 20 }
tx2.metric('burnt calories', () => body.calories)
tx2.action('lift weights', (cb) => {
cb({ success: true })
})
```
Check [API.md](API.md) for full API doc.
Once you have created some metrics:
```bash
$ pm2 start app.js
```
Then run:
```bash
# Inspect primitive reported
$ pm2 show app
```
or go to pm2.io for web based interface + insights creation.
## More
Generate documentation:
```bash
$ npm run doc
```
## License
MIT

41
api.hyungi.net/node_modules/tx2/example/events.js generated vendored Normal file
View File

@@ -0,0 +1,41 @@
const tx2 = require('..')
console.log(tx2)
tx2.emit('test', { data: 'yes' })
// Metrics variants
tx2.metric({
name: 'test',
val: () => {
return 20
}
})
tx2.metric('test2', () => {
return 30
})
let m = tx2.metric('test3', 0)
m.set(45)
// Histogram
let n = tx2.histogram({
name: 'histo1',
val: () => {
return Math.random()
}
})
// OR
n.update(Math.random() * 1000)
tx2.action('toto', (cb) => {
return cb({yessai:true})
})
setInterval(() => {} , 1000)

4
api.hyungi.net/node_modules/tx2/index.js generated vendored Normal file
View File

@@ -0,0 +1,4 @@
const PX2 = require('./src/')
module.exports = new PX2()

20
api.hyungi.net/node_modules/tx2/package.json generated vendored Normal file
View File

@@ -0,0 +1,20 @@
{
"name": "tx2",
"version": "1.0.5",
"description": "Metrics, Issues, Actions, Events reporting library",
"main": "index.js",
"scripts": {
"test": "mocha test/*.mocha.js",
"doc": "npx jsdoc2md src/* > API.md"
},
"author": "PM2",
"license": "MIT",
"dependencies": {
"json-stringify-safe": "^5.0.1"
},
"devDependencies": {
"jsdoc-to-markdown": "^6.0.1",
"mocha": "8",
"should": "13"
}
}

84
api.hyungi.net/node_modules/tx2/src/actions.js generated vendored Normal file
View File

@@ -0,0 +1,84 @@
module.exports = {
/**
* Expose an action/function triggerable via PM2 or PM2.io
* @memberof TX2
* @param {string} action_name Name of the action
* @param {object} [opts] Optional parameter
* @param {function} fn Function to be called
*
* @example <caption>Action without arguments</caption>
* tx2.action('run_query', (cb) => {
* cb({ success: true })
* })
* @example <caption>Action with arguments</caption>
* tx2.action('run_query', arg1, (cb) => {
* cb({ success: arg1 })
* })
*/
action(action_name, opts, fn) {
if (!fn) {
fn = opts
opts = null
}
if (!action_name)
return console.error('[PMX] action.action_name is missing')
if (!fn)
return console.error('[PMX] emit.data is mission')
// Notify the action
this.send({
type : 'axm:action',
data : {
action_name : action_name,
opts : opts,
arity : fn.length
}
})
let reply = (data) => {
if (data.length) {
data._length = data.length
delete data.length
}
this.send({
type : 'axm:reply',
data : {
return : data,
action_name : action_name
}
})
}
process.on('message', (data) => {
if (!data) return false
// Notify the action
if (data && (data == action_name || data.msg == action_name))
this.event('action triggered', { action_name, opts })
// In case 2 arguments has been set but no options has been transmitted
if (fn.length === 2 && typeof(data) === 'string' && data === action_name)
return fn({}, reply)
// In case 1 arguments has been set but options has been transmitted
if (fn.length === 1 && typeof(data) === 'object' && data.msg === action_name)
return fn(reply)
/**
* Classical call
*/
if (typeof(data) === 'string' && data === action_name)
return fn(reply)
/**
* If data is an object == v2 protocol
* Pass the opts as first argument
*/
if (typeof(data) === 'object' && data.msg === action_name)
return fn(data.opts, reply)
})
}
}

33
api.hyungi.net/node_modules/tx2/src/events.js generated vendored Normal file
View File

@@ -0,0 +1,33 @@
const stringify = require('json-stringify-safe')
module.exports = {
/**
* Sends an Event
* @memberof TX2
* @param {string} name Name of the event
* @param {object} data Metadata attached to the event
* @example
* tx2.event('event-name', { multi: 'data' })
*/
event(name, data) {
if (!name)
return console.error('[AXM] emit.name is missing')
let inflight_obj = {}
if (typeof(data) == 'object')
inflight_obj = JSON.parse(stringify(data))
else {
inflight_obj.data = data || null
}
inflight_obj.__name = name
this.send({
type : 'human:event',
data : inflight_obj
})
}
}

58
api.hyungi.net/node_modules/tx2/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,58 @@
const Events = require('./events.js')
const Actions = require('./actions.js')
const Metrics = require('./metrics.js')
const Issues = require('./issues.js')
const EventEmitter = require('events')
const stringify = require('json-stringify-safe')
/**
* @namespace TX2
* @class TX2
*/
class TX2 extends EventEmitter {
constructor() {
super()
Object.assign(this, Events)
Object.assign(this, Actions)
Object.assign(this, Metrics)
Object.assign(this, Issues)
var p_interval = setInterval(() => {
this.send({
type : 'axm:monitor',
data : Metrics.prepareData()
})
}, 990)
p_interval.unref()
}
/**
* Send JSON to PM2
* @private
* @param {object} args
*/
send(args) {
this.emit('data', args)
if (!process.send) {
var output = args.data
delete output.__name
return false
}
try {
process.send(JSON.parse(stringify(args)))
} catch(e) {
console.error('Process disconnected from parent !')
console.error(e.stack || e)
process.exit(1)
}
}
}
module.exports = TX2

62
api.hyungi.net/node_modules/tx2/src/issues.js generated vendored Normal file
View File

@@ -0,0 +1,62 @@
const jsonize = function(err, filter, space) {
if (typeof(err) != 'object')
return err
var plainObject = {}
Object.getOwnPropertyNames(err).forEach(function(key) {
plainObject[key] = err[key]
})
return plainObject
}
module.exports = {
_interpretError: function(err) {
var s_err = {}
if (typeof(err) === 'string') {
// Simple string processing
s_err.message = err
s_err.stack = err
}
else if (!(err instanceof Error) && typeof(err) === 'object') {
// JSON processing
s_err.message = err
s_err.stack = err
}
else if (err instanceof Error) {
// Error object type processing
err.stack
if (err.__error_callsites) {
var stackFrames = []
err.__error_callsites.forEach(function(callSite) {
stackFrames.push({ file_name: callSite.getFileName(), line_number: callSite.getLineNumber()})
})
err.stackframes = stackFrames
delete err.__error_callsites
}
s_err = err
}
return jsonize(s_err)
},
/**
* Sends an Issue
* @memberof TX2
* @param {string|Error} err Error object or string to notify
* @example
* tx2.issue(new Error('bad error')
*/
issue: function(err) {
var ret_err = this._interpretError(err)
this.send({
type : 'process:exception',
data : ret_err
})
return ret_err
}
}

240
api.hyungi.net/node_modules/tx2/src/metrics.js generated vendored Normal file
View File

@@ -0,0 +1,240 @@
var Counter = require('./utils/probes/Counter.js')
var Histogram = require('./utils/probes/Histogram.js')
var Meter = require('./utils/probes/Meter.js')
function getValue(value) {
if (typeof(value) == 'function')
return value()
return value
}
const DEFAULT_AGGREGATION = 'avg'
const AVAILABLE_AGG_TYPES = ['avg', 'min', 'max', 'sum', 'none']
const AVAILABLE_MEASUREMENTS = ['min', 'max','sum','count','variance','mean','stddev','median','p75','p95','p99','p999']
module.exports = {
_metrics: {},
prepareData: function() {
var cooked_data = {}
Object.keys(this._metrics).forEach((probe_name) => {
if (typeof(this._metrics[probe_name].value) == 'undefined')
return false
cooked_data[probe_name] = {
value: getValue(this._metrics[probe_name].value)
}
if (this._metrics[probe_name].unit)
cooked_data[probe_name].unit = this._metrics[probe_name].unit
/**
* Attach aggregation mode
*/
if (this._metrics[probe_name].agg_type &&
this._metrics[probe_name].agg_type != 'none')
cooked_data[probe_name].agg_type = this._metrics[probe_name].agg_type
if (this._metrics[probe_name].unit)
cooked_data[probe_name].unit = this._metrics[probe_name].unit
})
return cooked_data
},
/**
* This reflect data to keymetrics
* pmx.transpose('prop name', fn)
*
* or
*
* pmx.transpose({
* name : 'variable name',
* data : function() { return value }
* })
*/
transpose : function(variable_name, reporter) {
if (typeof variable_name === 'object') {
reporter = variable_name.data
variable_name = variable_name.name
}
if (typeof reporter !== 'function') {
return console.error('[PMX] reporter is not a function')
}
this._metrics[variable_name] = {
value: reporter
}
},
metricExists: function(metric_name) {
return !!this._metrics[metric_name]
},
/**
* @typedef {Object} Metric
* @property {function} val Return the current value
* @property {function} set Set value
*/
/**
* Expose a Metric
* @memberof TX2
* @param {string} name Name of the metric
* @param {function} [function] Optional function to trigger every second to retrieve updated value
* @returns {Metric} A metrics object
* @example
* tx2.metric('metric_name', () => obj.value)
* @example
* tx2.metric('metric_name', 'unit', () => obj.value)
* @example
* let mn = tx2.metric('metric_name')
* mn.set(20)
*/
metric : function(opts, unit, val) {
let name, value
// tx2.metric('metric-name', 'unit', () => variable)
if (typeof(opts) == 'string' && typeof(unit) == 'string') {
name = opts
unit = unit
value = val
}
else if (typeof(opts) == 'string' && typeof(unit) == 'function') {
name = opts
value = unit
}
else if (typeof(opts) == 'string' && typeof(unit) == 'number') {
name = opts
value = unit
}
else if (typeof(opts) === 'object') {
name = opts.name
value = opts.val || opts.value
unit = opts.unit || null
}
if (!name)
return console.error('[PX2][Metric] Name not defined')
this._metrics[name] = {
value: value,
unit: unit
}
return {
val : () => {
var value = this._metrics[name].value
if (typeof(value) == 'function')
value = value()
return value
},
set : (dt) => {
this._metrics[name].value = dt
}
}
},
/**
* Expose a Metric of type Histogram. This computes a value accross based on the measurement option and will return a value accordingly
@private
* @memberof TX2
* @param {string} [opts.name] Metric Name
* @param {string} [opts.measurement] Measurement made on time period, can be 'min', 'max','sum','count','variance','mean','stddev','median','p75','p95','p99','p999'
* @param {function} [opts.value] Function to call to retrieve new value every second
* @returns {}
*/
histogram : function(opts) {
if (!opts.name)
return console.error('[Metric][Histogram] Name not defined')
opts.measurement = opts.measurement || 'mean'
opts.unit = opts.unit || ''
if (AVAILABLE_MEASUREMENTS.indexOf(opts.measurement) == -1)
return console.error('[Metric][Histogram] Measure type %s does not exists', opts.measurement)
var histogram = new Histogram(opts)
this._metrics[opts.name] = {
value: () => {
if (opts.val || opts.value) {
var value = opts.val || opts.value
if (typeof(value) == 'function')
value = value()
histogram.update(value)
}
return (Math.round(histogram.val() * 100) / 100)
},
unit : opts.unit
}
return histogram
},
/**
* Expose a Metric of type: Meter. This (???)
* @private
* @param {string} opts.name Name of the Metric
* @returns {}
*/
meter : function(opts) {
if (!opts.name)
return console.error('[Metric][Meter] Name not defined')
opts.unit = opts.unit || ''
var meter = new Meter(opts)
this._metrics[opts.name] = {
value: function() {
return meter.val() + '' + opts.unit
},
unit : opts.unit
}
return meter
},
/**
* Expose a metric of type: Counter.
* @typedef {object} Counter
* @property {function} inc Increment value
* @property {function} dev Decrement value
*/
/**
* Expose a Metric of type: Counter. By calling .inc() or .dec() you update that value
* @memberof TX2
* @param {string} name Name of the Metric
* @returns {Counter}
*/
counter : function(opts) {
let name, unit, agg_type = DEFAULT_AGGREGATION
if (typeof(opts) == 'string')
name = opts
else {
name = opts.name
unit = opts.unit
}
if (!name)
return console.error('[Metric][Counter] Name not defined')
var counter = new Counter()
this._metrics[name] = {
value: function() { return counter.val() },
agg_type: agg_type,
unit : unit || null
}
return counter
}
}

View File

@@ -0,0 +1,132 @@
// Based on http://en.wikipedia.org/wiki/Binary_Heap
// as well as http://eloquentjavascript.net/appendix2.html
module.exports = BinaryHeap;
function BinaryHeap(options) {
options = options || {};
this._elements = options.elements || [];
this._score = options.score || this._score;
}
BinaryHeap.prototype.add = function(/* elements */) {
for (var i = 0; i < arguments.length; i++) {
var element = arguments[i];
this._elements.push(element);
this._bubble(this._elements.length - 1);
}
};
BinaryHeap.prototype.first = function() {
return this._elements[0];
};
BinaryHeap.prototype.removeFirst = function() {
var root = this._elements[0];
var last = this._elements.pop();
if (this._elements.length > 0) {
this._elements[0] = last;
this._sink(0);
}
return root;
};
BinaryHeap.prototype.clone = function() {
return new BinaryHeap({
elements: this.toArray(),
score: this._score,
});
};
BinaryHeap.prototype.toSortedArray = function() {
var array = [];
var clone = this.clone();
while (true) {
var element = clone.removeFirst();
if (element === undefined) break;
array.push(element);
}
return array;
};
BinaryHeap.prototype.toArray = function() {
return [].concat(this._elements);
};
BinaryHeap.prototype.size = function() {
return this._elements.length;
};
BinaryHeap.prototype._bubble = function(bubbleIndex) {
var bubbleElement = this._elements[bubbleIndex];
var bubbleScore = this._score(bubbleElement);
while (bubbleIndex > 0) {
var parentIndex = this._parentIndex(bubbleIndex);
var parentElement = this._elements[parentIndex];
var parentScore = this._score(parentElement);
if (bubbleScore <= parentScore) break;
this._elements[parentIndex] = bubbleElement;
this._elements[bubbleIndex] = parentElement;
bubbleIndex = parentIndex;
}
};
BinaryHeap.prototype._sink = function(sinkIndex) {
var sinkElement = this._elements[sinkIndex];
var sinkScore = this._score(sinkElement);
var length = this._elements.length;
while (true) {
var swapIndex = null;
var swapScore = null;
var swapElement = null;
var childIndexes = this._childIndexes(sinkIndex);
for (var i = 0; i < childIndexes.length; i++) {
var childIndex = childIndexes[i];
if (childIndex >= length) break;
var childElement = this._elements[childIndex];
var 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;
}
};
BinaryHeap.prototype._parentIndex = function(index) {
return Math.floor((index - 1) / 2);
};
BinaryHeap.prototype._childIndexes = function(index) {
return [
2 * index + 1,
2 * index + 2,
];
return ;
};
BinaryHeap.prototype._score = function(element) {
return element.valueOf();
};

View File

@@ -0,0 +1,26 @@
module.exports = Counter;
function Counter(opts) {
opts = opts || {};
this._count = opts.count || 0;
}
Counter.prototype.val = function() {
return this._count;
};
Counter.prototype.inc = function(n) {
const incBy = n == null ? 1 : n
this._count += incBy;
};
Counter.prototype.dec = function(n) {
const decBy = n == null ? 1 : n
this._count -= decBy;
};
Counter.prototype.reset = function(count) {
this._count = count || 0;
};

110
api.hyungi.net/node_modules/tx2/src/utils/probes/EDS.js generated vendored Normal file
View File

@@ -0,0 +1,110 @@
var BinaryHeap = require('./BinaryHeap');
var units = require('./units');
module.exports = ExponentiallyDecayingSample;
function ExponentiallyDecayingSample(options) {
options = options || {};
this._elements = new BinaryHeap({
score: function(element) {
return -element.priority;
}
});
this._rescaleInterval = options.rescaleInterval || ExponentiallyDecayingSample.RESCALE_INTERVAL;
this._alpha = options.alpha || ExponentiallyDecayingSample.ALPHA;
this._size = options.size || ExponentiallyDecayingSample.SIZE;
this._random = options.random || this._random;
this._landmark = null;
this._nextRescale = null;
this._mean = null;
}
ExponentiallyDecayingSample.RESCALE_INTERVAL = 1 * units.HOURS;
ExponentiallyDecayingSample.ALPHA = 0.015;
ExponentiallyDecayingSample.SIZE = 1028;
ExponentiallyDecayingSample.prototype.update = function(value, timestamp) {
var now = Date.now();
if (!this._landmark) {
this._landmark = now;
this._nextRescale = this._landmark + this._rescaleInterval;
}
timestamp = timestamp || now;
var newSize = this._elements.size() + 1;
var 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);
};
ExponentiallyDecayingSample.prototype.toSortedArray = function() {
return this._elements
.toSortedArray()
.map(function(element) {
return element.value;
});
};
ExponentiallyDecayingSample.prototype.toArray = function() {
return this._elements
.toArray()
.map(function(element) {
return element.value;
});
};
ExponentiallyDecayingSample.prototype._weight = function(age) {
// We divide by 1000 to not run into huge numbers before reaching a
// rescale event.
return Math.exp(this._alpha * (age / 1000));
};
ExponentiallyDecayingSample.prototype._priority = function(age) {
return this._weight(age) / this._random();
};
ExponentiallyDecayingSample.prototype._random = function() {
return Math.random();
};
ExponentiallyDecayingSample.prototype._rescale = function(now) {
now = now || Date.now();
var self = this;
var oldLandmark = this._landmark;
this._landmark = now || Date.now();
this._nextRescale = now + this._rescaleInterval;
var factor = self._priority(-(self._landmark - oldLandmark));
this._elements
.toArray()
.forEach(function(element) {
element.priority *= factor;
});
};
ExponentiallyDecayingSample.prototype.avg = function(now) {
var sum = 0;
this._elements
.toArray()
.forEach(function(element) {
sum += element.value;
});
return (sum / this._elements.size());
}

View File

@@ -0,0 +1,29 @@
var units = require('./units');
module.exports = ExponentiallyWeightedMovingAverage;
function ExponentiallyWeightedMovingAverage(timePeriod, tickInterval) {
this._timePeriod = timePeriod || 1 * units.MINUTE;
this._tickInterval = tickInterval || ExponentiallyWeightedMovingAverage.TICK_INTERVAL;
this._alpha = 1 - Math.exp(-this._tickInterval / this._timePeriod);
this._count = 0;
this._rate = 0;
};
ExponentiallyWeightedMovingAverage.TICK_INTERVAL = 5 * units.SECONDS;
ExponentiallyWeightedMovingAverage.prototype.update = function(n) {
this._count += n;
};
ExponentiallyWeightedMovingAverage.prototype.tick = function() {
var instantRate = this._count / this._tickInterval;
this._count = 0;
this._rate += (this._alpha * (instantRate - this._rate));
};
ExponentiallyWeightedMovingAverage.prototype.rate = function(timeUnit) {
return (this._rate || 0) * timeUnit;
};

View File

@@ -0,0 +1,196 @@
var EDS = require('./EDS.js');
function Histogram(opts) {
var self = this;
opts = opts || {};
this._measurement = opts.measurement;
this._call_fn = null;
var methods = {
min : this.getMin,
max : this.getMax,
sum : this.getSum,
count : this.getCount,
variance : this._calculateVariance,
mean : this._calculateMean,
stddev : this._calculateStddev,
ema : this.getEma()
};
if (methods[this._measurement])
this._call_fn = methods[this._measurement];
else {
this._call_fn = function() {
var percentiles = this.percentiles([0.5, 0.75, 0.95, 0.99, 0.999]);
var medians = {
median : percentiles[0.5],
p75 : percentiles[0.75],
p95 : percentiles[0.95],
p99 : percentiles[0.99],
p999 : percentiles[0.999]
};
return medians[this._measurement];
}
}
this._sample = new EDS();
this._min = null;
this._max = null;
this._count = 0;
this._sum = 0;
// These are for the Welford algorithm for calculating running variance
// without floating-point doom.
this._varianceM = 0;
this._varianceS = 0;
this._ema = 0;
}
Histogram.prototype.update = function(value) {
this._count++;
this._sum += value;
this._sample.update(value);
this._updateMin(value);
this._updateMax(value);
this._updateVariance(value);
this._updateEma(value);
};
Histogram.prototype.percentiles = function(percentiles) {
var values = this._sample
.toArray()
.sort(function(a, b) {
return (a === b)
? 0
: a - b;
});
var results = {};
for (var i = 0; i < percentiles.length; i++) {
var percentile = percentiles[i];
if (!values.length) {
results[percentile] = null;
continue;
}
var pos = percentile * (values.length + 1);
if (pos < 1) {
results[percentile] = values[0];
} else if (pos >= values.length) {
results[percentile] = values[values.length - 1];
} else {
var lower = values[Math.floor(pos) - 1];
var upper = values[Math.ceil(pos) - 1];
results[percentile] = lower + (pos - Math.floor(pos)) * (upper - lower);
}
}
return results;
};
Histogram.prototype.reset = function() {
this.constructor.call(this);
};
Histogram.prototype.val = function() {
if (typeof(this._call_fn) === 'function')
return this._call_fn();
else
return this._call_fn;
};
Histogram.prototype.getMin = function() {
return this._min;
};
Histogram.prototype.getMax = function() {
return this._max;
};
Histogram.prototype.getSum = function() {
return this._sum;
};
Histogram.prototype.getCount = function() {
return this._count;
};
Histogram.prototype.getEma = function() {
return this._ema;
}
Histogram.prototype.fullResults = function() {
var percentiles = this.percentiles([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],
ema : this._ema
};
};
Histogram.prototype._updateMin = function(value) {
if (this._min === null || value < this._min) {
this._min = value;
//console.log(value);
}
};
Histogram.prototype._updateMax = function(value) {
if (this._max === null || value > this._max) {
this._max = value;
}
};
Histogram.prototype._updateVariance = function(value) {
if (this._count === 1) return this._varianceM = value;
var oldM = this._varianceM;
this._varianceM += ((value - oldM) / this._count);
this._varianceS += ((value - oldM) * (value - this._varianceM));
};
Histogram.prototype._updateEma = function(value) {
if (this._count <= 1) return this._ema = this._calculateMean();
var alpha = 2 / (1 + this._count);
this._ema = value * alpha + this._ema * (1 - alpha);
}
Histogram.prototype._calculateMean = function() {
return (this._count === 0)
? 0
: this._sum / this._count;
};
Histogram.prototype._calculateVariance = function() {
return (this._count <= 1)
? null
: this._varianceS / (this._count - 1);
};
Histogram.prototype._calculateStddev = function() {
return (this._count < 1)
? null
: Math.sqrt(this._calculateVariance());
};
module.exports = Histogram;

View File

@@ -0,0 +1,33 @@
var units = require('./units')
var EWMA = require('./EWMA')
function Meter(opts) {
var self = this
this._tickInterval = units.SECONDS
this._samples = opts.seconds || 1
this._timeframe = opts.timeframe || 60
this._rate = new EWMA(units.SECONDS, this._tickInterval)
this._interval = setInterval(function() {
self._rate.tick()
}, this._tickInterval)
this._interval.unref()
}
Meter.RATE_UNIT = units.SECONDS
Meter.prototype.mark = function(n) {
n = n || 1
this._rate.update(n)
}
Meter.prototype.val = function() {
return Math.round(this._rate.rate(Meter.RATE_UNIT) * 100 ) / 100
}
module.exports = Meter

View File

@@ -0,0 +1,9 @@
// Time units, as found in Java:
// see: http://download.oracle.com/javase/6/docs/api/java/util/concurrent/TimeUnit.html
exports.NANOSECONDS = 1 / (1000 * 1000);
exports.MICROSECONDS = 1 / 1000;
exports.MILLISECONDS = 1;
exports.SECONDS = 1000 * exports.MILLISECONDS;
exports.MINUTES = 60 * exports.SECONDS;
exports.HOURS = 60 * exports.MINUTES;
exports.DAYS = 24 * exports.HOURS;

18
api.hyungi.net/node_modules/tx2/test/action.mocha.js generated vendored Normal file
View File

@@ -0,0 +1,18 @@
const tx2 = require('..')
const should = require('should')
describe('Action', function() {
it('should notify about new action', (done) => {
tx2.once('data', (dt) => {
should(dt.type).eql('axm:action')
should(dt.data.action_name).eql('something special')
done()
})
tx2.action('something special', (cb) => {
cb({sucess:true})
})
})
})

25
api.hyungi.net/node_modules/tx2/test/event.mocha.js generated vendored Normal file
View File

@@ -0,0 +1,25 @@
const tx2 = require('..')
const should = require('should')
describe('Event', function() {
it('should emit an event without data', (done) => {
tx2.once('data', (dt) => {
should(dt.type).eql('human:event')
done()
})
tx2.event('something special')
})
it('should emit an event with data', (done) => {
tx2.once('data', (dt) => {
should(dt.type).eql('human:event')
should(dt.data.yes).eql(true)
done()
})
tx2.event('something special', { yes : true })
})
})

25
api.hyungi.net/node_modules/tx2/test/issue.mocha.js generated vendored Normal file
View File

@@ -0,0 +1,25 @@
const tx2 = require('..')
const should = require('should')
describe('Issue', function() {
it('should trigger an issue', (done) => {
tx2.once('data', (dt) => {
should(dt.type).eql('process:exception')
should(dt.stack).not.eql(null)
done()
})
tx2.issue(new Error('shit happens'))
})
it('should trigger an issue v2', (done) => {
tx2.once('data', (dt) => {
should(dt.type).eql('process:exception')
should(dt.stack).not.eql(null)
done()
})
tx2.issue('shit happens')
})
})

90
api.hyungi.net/node_modules/tx2/test/metric.mocha.js generated vendored Normal file
View File

@@ -0,0 +1,90 @@
const tx2 = require('..')
const should = require('should')
describe('Metric', function() {
this.timeout(4000)
it('should register a metric', () => {
tx2.metric({
name: 'test',
val: () => {
return 20
}
})
})
it('should metric exists', () => {
should(tx2.metricExists('test')).eql(true)
})
it('should unknown metric not exists', () => {
should(tx2.metricExists('unknowsss')).eql(false)
})
it('should have metric present', (done) => {
tx2.once('data', (dt) => {
should(dt.type).eql('axm:monitor')
should(dt.data.test.value).eql(20)
done()
})
})
it('should register metric v2', () => {
tx2.metric('test2', () => {
return 30
})
})
it('should have metric present', (done) => {
tx2.once('data', (dt) => {
should(dt.type).eql('axm:monitor')
should(dt.data.test2.value).eql(30)
done()
})
})
it('should register metric v3', () => {
let m = tx2.metric('test3', 0)
m.set(45)
})
it('should have metric present', (done) => {
tx2.once('data', (dt) => {
should(dt.type).eql('axm:monitor')
should(dt.data.test3.value).eql(45)
done()
})
})
})
describe('counter', () => {
describe('inc', () => {
const test = ({incBy, expectedValue}) => () => {
const counter = tx2.counter('Test counter')
counter.inc(incBy)
should(counter.val()).eql(expectedValue)
}
it('should increment by 1 when called with no arguments', test({expectedValue: 1}))
it('should increment by 1 when called with 1', test({incBy: 1, expectedValue: 1}))
it('should increment by -1 when called with -1', test({incBy: -1, expectedValue: -1}))
it('should increment by 0 when called with 0', test({incBy: 0, expectedValue: 0}))
it('should increment by 17.3 when called with 17.3', test({incBy: 17.3, expectedValue: 17.3}))
})
describe('dec', () => {
const test = ({decBy, expectedValue}) => () => {
const counter = tx2.counter('Test counter')
counter.dec(decBy)
should(counter.val()).eql(expectedValue)
}
it('should decrement by 1 when called with no arguments', test({expectedValue: -1}))
it('should decrement by 1 when called with 1', test({decBy: 1, expectedValue: -1}))
it('should decrement by -1 when called with -1', test({decBy: 1, expectedValue: -1}))
it('should decrement by 0 when called with 0', test({decBy: 0, expectedValue: 0}))
it('should decrement by 17.3 when called with 17.3', test({decBy: 17.3, expectedValue: -17.3}))
})
})