UNPKG

11.4 kBJavaScriptView Raw
1"use strict";
2
3var helpers = require('./helpers');
4
5function applyStatsFns (Client) {
6 /**
7 * Represents the timing stat
8 * @param stat {String|Array} The stat(s) to send
9 * @param time {Number} The time in milliseconds to send
10 * @param sampleRate {Number=} The Number of times to sample (0 to 1). Optional.
11 * @param tags {Array=} The Array of tags to add to metrics. Optional.
12 * @param callback {Function=} Callback when message is done being delivered. Optional.
13 */
14 Client.prototype.timing = function (stat, time, sampleRate, tags, callback) {
15 this.sendAll(stat, time, 'ms', sampleRate, tags, callback);
16 };
17
18 /**
19 * Represents the timing stat by recording the duration a function takes to run (in milliseconds)
20 * @param func {Function} The function to run
21 * @param stat {String|Array} The stat(s) to send
22 * @param sampleRate {Number=} The Number of times to sample (0 to 1). Optional.
23 * @param tags {Array=} The Array of tags to add to metrics. Optional.
24 * @param callback {Function=} Callback when message is done being delivered. Optional.
25 */
26 Client.prototype.timer = function (func, stat, sampleRate, tags, callback) {
27 var _this = this;
28
29 return function () {
30 var start = process.hrtime();
31 try {
32 return func.apply(null, arguments);
33 } finally {
34 // get duration in milliseconds
35 var durationComponents = process.hrtime(start);
36 var seconds = durationComponents[0];
37 var nanoseconds = durationComponents[1];
38 var duration = seconds * 1000 + nanoseconds / 1E6;
39
40 _this.timing(
41 stat,
42 duration,
43 sampleRate,
44 tags,
45 callback
46 );
47 }
48 };
49 };
50
51 /**
52 * Decorates an async function with timing recording behaviour.
53 *
54 * This version of `timer` will record the time take for the asyncronus action returned by `func`
55 * not just the execution time of `func` itself.
56 *
57 * @param func {<T,A>(...A):Promise<T>} The function to run
58 * @param stat {String|Array} The stat(s) to send
59 * @param sampleRate {Number=} The Number of times to sample (0 to 1). Optional.
60 * @param tags {Array=} The Array of tags to add to metrics. Optional.
61 * @param callback {Function=} Callback when message is done being delivered. Optional.
62 */
63 Client.prototype.asyncTimer = function (func, stat, sampleRate, tags, callback) {
64 var self = this;
65 return function() {
66 var end = hrtimer();
67 var p = func.apply(null, arguments);
68 var recordStat = function() { self.timing(stat, end(), sampleRate, tags, callback); };
69 p.then(recordStat, recordStat);
70 return p;
71 };
72 };
73
74 function hrtimer() {
75 var start = process.hrtime();
76
77 return function () {
78 var durationComponents = process.hrtime(start);
79 var seconds = durationComponents[0];
80 var nanoseconds = durationComponents[1];
81 var duration = seconds * 1000 + nanoseconds / 1E6;
82 return duration;
83 };
84 }
85
86
87 /**
88 * Increments a stat by a specified amount
89 * @param stat {String|Array} The stat(s) to send
90 * @param value The value to send
91 * @param sampleRate {Number=} The Number of times to sample (0 to 1). Optional.
92 * @param tags {Array=} The Array of tags to add to metrics. Optional.
93 * @param callback {Function=} Callback when message is done being delivered. Optional.
94 */
95 Client.prototype.increment = function (stat, value, sampleRate, tags, callback) {
96 // allow use of tags without explicit value or sampleRate
97 if (arguments.length < 3) {
98 if (typeof value !== 'number') {
99 tags = value;
100 value = undefined;
101 }
102 }
103 // we explicitly check for undefined and null (and don't do a "! value" check)
104 // so that 0 values are allowed and sent through as-is
105 if (value === undefined || value === null) {
106 value = 1;
107 }
108 this.sendAll(stat, value, 'c', sampleRate, tags, callback);
109 };
110
111 /**
112 * Decrements a stat by a specified amount
113 * @param stat {String|Array} The stat(s) to send
114 * @param value The value to send
115 * @param sampleRate {Number=} The Number of times to sample (0 to 1). Optional.
116 * @param tags {Array=} The Array of tags to add to metrics. Optional.
117 * @param callback {Function=} Callback when message is done being delivered. Optional.
118 */
119 Client.prototype.decrement = function (stat, value, sampleRate, tags, callback) {
120 this.sendAll(stat, -value || -1, 'c', sampleRate, tags, callback);
121 };
122
123 /**
124 * Represents the histogram stat
125 * @param stat {String|Array} The stat(s) to send
126 * @param value The value to send
127 * @param sampleRate {Number=} The Number of times to sample (0 to 1). Optional.
128 * @param tags {Array=} The Array of tags to add to metrics. Optional.
129 * @param callback {Function=} Callback when message is done being delivered. Optional.
130 */
131 Client.prototype.histogram = function (stat, value, sampleRate, tags, callback) {
132 this.sendAll(stat, value, 'h', sampleRate, tags, callback);
133 };
134
135 /**
136 * Represents the distribution stat
137 * @param stat {String|Array} The stat(s) to send
138 * @param value The value to send
139 * @param sampleRate {Number=} The Number of times to sample (0 to 1). Optional.
140 * @param tags {Array=} The Array of tags to add to metrics. Optional.
141 * @param callback {Function=} Callback when message is done being delivered. Optional.
142 */
143 Client.prototype.distribution = function (stat, value, sampleRate, tags, callback) {
144 this.sendAll(stat, value, 'd', sampleRate, tags, callback);
145 };
146
147
148 /**
149 * Gauges a stat by a specified amount
150 * @param stat {String|Array} The stat(s) to send
151 * @param value The value to send
152 * @param sampleRate {Number=} The Number of times to sample (0 to 1). Optional.
153 * @param tags {Array=} The Array of tags to add to metrics. Optional.
154 * @param callback {Function=} Callback when message is done being delivered. Optional.
155 */
156 Client.prototype.gauge = function (stat, value, sampleRate, tags, callback) {
157 this.sendAll(stat, value, 'g', sampleRate, tags, callback);
158 };
159
160 /**
161 * Counts unique values by a specified amount
162 * @param stat {String|Array} The stat(s) to send
163 * @param value The value to send
164 * @param sampleRate {Number=} The Number of times to sample (0 to 1). Optional.
165 * @param tags {Array=} The Array of tags to add to metrics. Optional.
166 * @param callback {Function=} Callback when message is done being delivered. Optional.
167 */
168 Client.prototype.unique = Client.prototype.set = function (stat, value, sampleRate, tags, callback) {
169 this.sendAll(stat, value, 's', sampleRate, tags, callback);
170 };
171
172 /**
173 * Send a service check
174 * @param name {String} The name of the service check
175 * @param status {Number=} The status of the service check (0 to 3).
176 * @param options
177 * @option date_happened {Date} Assign a timestamp to the event. Default is now.
178 * @option hostname {String} Assign a hostname to the check.
179 * @option message {String} Assign a message to the check.
180 * @param tags {Array=} The Array of tags to add to the check. Optional.
181 * @param callback {Function=} Callback when message is done being delivered. Optional.
182 */
183 Client.prototype.check = function (name, status, options, tags, callback) {
184 if (this.telegraf) {
185 var err = new Error('Not supported by Telegraf / InfluxDB');
186 if (callback) {
187 return callback(err);
188 }
189 else if (this.errorHandler) {
190 return this.errorHandler(err);
191 }
192
193 throw err;
194 }
195
196 var check = ['_sc', this.prefix + name + this.suffix, status],
197 metadata = options || {};
198
199 if (metadata.date_happened) {
200 var timestamp = helpers.formatDate(metadata.date_happened);
201 if (timestamp) {
202 check.push('d:' + timestamp);
203 }
204 }
205 if (metadata.hostname) {
206 check.push('h:' + metadata.hostname);
207 }
208
209 var mergedTags = this.globalTags;
210 if (tags && typeof(tags) === "object") {
211 mergedTags = helpers.overrideTags(mergedTags, tags, this.telegraf);
212 }
213 if (mergedTags.length > 0) {
214 check.push('#' + mergedTags.join(','));
215 }
216
217 // message has to be the last part of a service check
218 if (metadata.message) {
219 check.push('m:' + metadata.message);
220 }
221
222 // allow for tags to be omitted and callback to be used in its place
223 if(typeof tags === 'function' && callback === undefined) {
224 callback = tags;
225 }
226
227 var message = check.join('|');
228 // Service checks are unique in that message has to be the last element in
229 // the stat if provided, so we can't append tags like other checks. This
230 // directly calls the `_send` method to avoid appending tags, since we've
231 // already added them.
232 this._send(message, callback);
233 };
234
235 /**
236 * Send on an event
237 * @param title {String} The title of the event
238 * @param text {String} The description of the event. Optional- title is used if not given.
239 * @param options
240 * @option date_happened {Date} Assign a timestamp to the event. Default is now.
241 * @option hostname {String} Assign a hostname to the event.
242 * @option aggregation_key {String} Assign an aggregation key to the event, to group it with some others.
243 * @option priority {String} Can be ‘normal’ or ‘low’. Default is 'normal'.
244 * @option source_type_name {String} Assign a source type to the event.
245 * @option alert_type {String} Can be ‘error’, ‘warning’, ‘info’ or ‘success’. Default is 'info'.
246 * @param tags {Array=} The Array of tags to add to metrics. Optional.
247 * @param callback {Function=} Callback when message is done being delivered. Optional.
248 */
249 Client.prototype.event = function (title, text, options, tags, callback) {
250 if (this.telegraf) {
251 var err = new Error('Not supported by Telegraf / InfluxDB');
252 if (callback) {
253 return callback(err);
254 }
255 else if (this.errorHandler) {
256 return this.errorHandler(err);
257 }
258
259 throw err;
260 }
261
262 // Convert to strings
263 var message,
264 msgTitle = String(title ? title : ''),
265 msgText = String(text ? text : msgTitle);
266 // Escape new lines (unescaping is supported by DataDog)
267 msgText = msgText.replace(/\n/g, '\\n');
268
269 // start out the message with the event-specific title and text info
270 message = '_e{' + msgTitle.length + ',' + msgText.length + '}:' + msgTitle + '|' + msgText;
271
272 // add in the event-specific options
273 if (options) {
274 if (options.date_happened) {
275 var timestamp = helpers.formatDate(options.date_happened);
276 if (timestamp) {
277 message += '|d:' + timestamp;
278 }
279 }
280 if (options.hostname) {
281 message += '|h:' + options.hostname;
282 }
283 if (options.aggregation_key) {
284 message += '|k:' + options.aggregation_key;
285 }
286 if (options.priority) {
287 message += '|p:' + options.priority;
288 }
289 if (options.source_type_name) {
290 message += '|s:' + options.source_type_name;
291 }
292 if (options.alert_type) {
293 message += '|t:' + options.alert_type;
294 }
295 }
296
297 // allow for tags to be omitted and callback to be used in its place
298 if(typeof tags === 'function' && callback === undefined) {
299 callback = tags;
300 }
301
302 this.send(message, tags, callback);
303 };
304}
305
306module.exports = applyStatsFns;