1
+ 'use strict' ;
2
+ var measured = require ( 'measured' ) ;
3
+ // var metricsCollection = measured.createCollection();
4
+ var gc = ( require ( 'gc-stats' ) ) ( ) ;
5
+ var eventLoopStats = require ( "event-loop-stats" ) ;
6
+ var memwatch = require ( 'memwatch-next' ) ;
7
+ var schedule = require ( 'node-schedule' ) ;
8
+ var usage = require ( 'pidusage' ) ;
9
+ var metrics = { } ;
10
+ var trackedMetrics = { } ;
11
+ var interval = 1000 ; // how often to refresh our measurement
12
+ var cpuUsage ;
13
+
14
+
15
+ var CATEGORIES = {
16
+ all : 'global.all' ,
17
+ statuses : 'statuses' ,
18
+ methods : 'methods' ,
19
+ endpoints : 'endpoints'
20
+ } ;
21
+
22
+ var NAMESPACES = {
23
+ process : 'process' ,
24
+ internalMetrics : 'internalMetrics' ,
25
+ apiMetrics : 'apiMetrics'
26
+ }
27
+
28
+ var cpuUsageScheduleJob ;
29
+
30
+ metrics . getAll = function ( reset ) {
31
+ var metricsAsJson = JSON . stringify ( trackedMetrics ) ;
32
+ if ( reset )
33
+ resetAll ( ) ;
34
+ return metricsAsJson ;
35
+ }
36
+
37
+ metrics . processMetrics = function ( reset ) {
38
+ var metricsAsJson = JSON . stringify ( trackedMetrics [ NAMESPACES . process ] ) ;
39
+ if ( reset )
40
+ resetProcessMetrics ( ) ;
41
+ return metricsAsJson ;
42
+ }
43
+
44
+ metrics . apiMetrics = function ( reset ) {
45
+ var metricsAsJson = JSON . stringify ( trackedMetrics [ NAMESPACES . apiMetrics ] ) ;
46
+ if ( reset )
47
+ resetMetric ( NAMESPACES . apiMetrics ) ;
48
+ return metricsAsJson ;
49
+ }
50
+
51
+ metrics . internalMetrics = function ( reset ) {
52
+ var metricsAsJson = JSON . stringify ( trackedMetrics [ NAMESPACES . internalMetrics ] ) ;
53
+ if ( reset )
54
+ resetMetric ( NAMESPACES . internalMetrics ) ;
55
+ return metricsAsJson ;
56
+ }
57
+
58
+ metrics . logInternalMetric = function ( info , err ) {
59
+ var status = "success" ;
60
+
61
+ if ( err ) {
62
+ status = "failure" ;
63
+ }
64
+
65
+ addInnerIO ( {
66
+ destenation : info . source ,
67
+ method : info . methodName ,
68
+ status : status ,
69
+ elapsedTime : Date . now ( ) - info . startTime
70
+ } ) ;
71
+ }
72
+
73
+ metrics . addApiData = function ( message ) {
74
+ var metricName = getMetricName ( message . route , message . method ) ;
75
+ // var path = message.route ? message.route.path : undefined;
76
+
77
+ updateMetric ( NAMESPACES . apiMetrics + '.' + CATEGORIES . all , message . time ) ;
78
+ updateMetric ( NAMESPACES . apiMetrics + '.' + CATEGORIES . statuses + '.' + message . status , message . time ) ;
79
+ updateMetric ( NAMESPACES . apiMetrics + '.' + CATEGORIES . methods + '.' + message . method , message . time ) ;
80
+ updateMetric ( NAMESPACES . apiMetrics + '.' + CATEGORIES . endpoints + '.' + metricName , message . time ) ;
81
+ } ;
82
+
83
+ function getMetricName ( route , methodName ) {
84
+ return route + '|' + methodName . toLowerCase ( ) ;
85
+ } ;
86
+
87
+ function addInnerIO ( message ) {
88
+ updateMetric ( NAMESPACES . internalMetrics + '.' + message . destenation + '.' + CATEGORIES . all , message . elapsedTime ) ;
89
+ updateMetric ( NAMESPACES . internalMetrics + '.' + message . destenation + '.' + CATEGORIES . statuses + '.' + message . status , message . elapsedTime ) ;
90
+ updateMetric ( NAMESPACES . internalMetrics + '.' + message . destenation + '.' + CATEGORIES . methods + '.' + message . method , message . elapsedTime )
91
+ }
92
+
93
+ function _evtparse ( eventName ) {
94
+ var namespaces = eventName . split ( '.' ) ;
95
+
96
+ var name1 ;
97
+ var levels = namespaces . length ;
98
+ var name = namespaces . pop ( ) ,
99
+ category = namespaces . pop ( ) ,
100
+ namespace = namespaces . pop ( ) ;
101
+
102
+ if ( levels == 4 ) {
103
+ name1 = name ;
104
+ name = category ;
105
+ category = namespace ;
106
+ namespace = namespaces . pop ( ) ;
107
+ }
108
+
109
+ return {
110
+ ns : namespace ,
111
+ name : name ,
112
+ name1 : name1 ,
113
+ category : category
114
+ }
115
+ }
116
+
117
+ function addMetric ( eventName , metric ) {
118
+ var parts = _evtparse ( eventName ) ;
119
+ var metricsPath ;
120
+
121
+ if ( ! trackedMetrics [ parts . ns ] ) {
122
+ trackedMetrics [ parts . ns ] = { } ;
123
+ }
124
+ if ( ! trackedMetrics [ parts . ns ] [ parts . category ] ) {
125
+ trackedMetrics [ parts . ns ] [ parts . category ] = { } ;
126
+ }
127
+ if ( ! trackedMetrics [ parts . ns ] [ parts . category ] [ parts . name ] ) {
128
+ if ( parts . name1 ) {
129
+ trackedMetrics [ parts . ns ] [ parts . category ] [ parts . name ] = { }
130
+ }
131
+ else {
132
+ trackedMetrics [ parts . ns ] [ parts . category ] [ parts . name ] = metric ;
133
+ }
134
+ }
135
+
136
+ if ( ( parts . name1 ) && ( ! trackedMetrics [ parts . ns ] [ parts . category ] [ parts . name ] [ parts . name1 ] ) ) {
137
+ trackedMetrics [ parts . ns ] [ parts . category ] [ parts . name ] [ parts . name1 ] = metric ;
138
+ }
139
+
140
+ if ( parts . name1 ) {
141
+ return trackedMetrics [ parts . ns ] [ parts . category ] [ parts . name ] [ parts . name1 ] ;
142
+ }
143
+ else {
144
+ return trackedMetrics [ parts . ns ] [ parts . category ] [ parts . name ] ;
145
+ }
146
+ }
147
+
148
+ function updateMetric ( name , elapsedTime ) {
149
+ var metric = addMetric ( name , new measured . Timer ( ) ) ;
150
+ metric . update ( elapsedTime ) ;
151
+ }
152
+
153
+ function addProcessMetrics ( ) {
154
+ memwatch . on ( 'leak' , function ( info ) {
155
+ trackedMetrics [ NAMESPACES . process ] [ "memory" ] [ "leak" ] = info ;
156
+ } ) ;
157
+
158
+ gc . removeAllListeners ( 'stats' ) ;
159
+ gc . on ( 'stats' , function ( stats ) {
160
+ updateMetric ( NAMESPACES . process + ".gc.time" , stats . pauseMS ) ;
161
+ //in bytes
162
+ updateMetric ( NAMESPACES . process + ".gc.releasedMem" , stats . diff . usedHeapSize ) ;
163
+ } ) ;
164
+
165
+ addMetric ( NAMESPACES . process + ".cpu.usage" , new measured . Gauge ( function ( ) {
166
+ return cpuUsage ;
167
+ } ) )
168
+
169
+ addMetric ( NAMESPACES . process + ".memory.usage" , new measured . Gauge ( function ( ) {
170
+ //in bytes
171
+ return process . memoryUsage ( ) ;
172
+ } ) ) ;
173
+
174
+ addMetric ( NAMESPACES . process + ".eventLoop.latency" , new measured . Gauge ( function ( ) {
175
+ return eventLoopStats . sense ( ) ;
176
+ } ) ) ;
177
+
178
+ setCpuUsageScheduleJob ( ) ;
179
+ }
180
+
181
+ function setCpuUsageScheduleJob ( ) {
182
+ if ( cpuUsageScheduleJob ) {
183
+ cpuUsageScheduleJob . cancel ( ) ;
184
+ }
185
+ cpuUsageScheduleJob = schedule . scheduleJob ( '*/1 * * * *' , function ( ) {
186
+ var pid = process . pid ;
187
+ usage . stat ( pid , function ( err , result ) {
188
+ cpuUsage = result . cpu ;
189
+ } ) ;
190
+ } ) ;
191
+ }
192
+
193
+ function resetAll ( ) {
194
+ resetProcessMetrics ( ) ;
195
+ resetMetric ( NAMESPACES . apiMetrics ) ;
196
+ resetMetric ( NAMESPACES . internalMetrics ) ;
197
+ }
198
+
199
+ function resetProcessMetrics ( ) {
200
+ resetMetric ( NAMESPACES . process ) ;
201
+ addProcessMetrics ( ) ;
202
+ }
203
+
204
+ function resetMetric ( namespaceToReset ) {
205
+ delete trackedMetrics [ namespaceToReset ] ;
206
+ }
207
+
208
+ addProcessMetrics ( ) ;
209
+
210
+ module . exports = metrics ;
0 commit comments