Răsfoiți Sursa

Merge pull request #12 from sharelatex/ho-stackdriver2

Add time support for promethious and refactor
Henry Oswald 7 ani în urmă
părinte
comite
254a508a01

+ 1 - 3
libraries/metrics/http.coffee

@@ -10,9 +10,7 @@ module.exports.monitor = (logger) ->
 			responseTime = new Date() - startTime
 			responseTime = new Date() - startTime
 			if req.route?.path?
 			if req.route?.path?
 				routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1)
 				routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1)
-				key = "http-requests.#{routePath}.#{req.method}.#{res.statusCode}"
-
-				Metrics.timing(key, responseTime)
+				Metrics.timing("http_request", responseTime, null, {method:req.method, status_code: res.statusCode, path:routePath})
 				logger.log
 				logger.log
 					req:
 					req:
 						url: req.originalUrl || req.url
 						url: req.originalUrl || req.url

+ 65 - 43
libraries/metrics/metrics.coffee

@@ -1,6 +1,3 @@
-StatsD = require('lynx')
-statsd = new StatsD(process.env["STATSD_HOST"] or "localhost", 8125, {on_error:->})
-
 traceAgent = require('@google-cloud/trace-agent')
 traceAgent = require('@google-cloud/trace-agent')
 debugAgent = require('@google-cloud/debug-agent')
 debugAgent = require('@google-cloud/debug-agent')
 
 
@@ -8,14 +5,13 @@ prom = require('prom-client')
 Register = require('prom-client').register
 Register = require('prom-client').register
 collectDefaultMetrics = prom.collectDefaultMetrics
 collectDefaultMetrics = prom.collectDefaultMetrics
 
 
-name = "unknown"
+appname = "unknown"
 hostname = require('os').hostname()
 hostname = require('os').hostname()
 
 
 buildKey = (key)-> "#{name}.#{hostname}.#{key}"
 buildKey = (key)-> "#{name}.#{hostname}.#{key}"
 buildGlobalKey = (key)-> "#{name}.global.#{key}"
 buildGlobalKey = (key)-> "#{name}.global.#{key}"
 
 
-counters = {}
-gauges = {}
+promMetrics = {}
 
 
 destructors = []
 destructors = []
 
 
@@ -23,17 +19,17 @@ require "./uv_threadpool_size"
 
 
 module.exports = Metrics =
 module.exports = Metrics =
 	initialize: (_name) ->
 	initialize: (_name) ->
-		name = _name
+		appname = _name
+		collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()})
 		traceAgent.start()
 		traceAgent.start()
 		debugAgent.start({
 		debugAgent.start({
 			serviceContext: {
 			serviceContext: {
 				allowExpressions: true,
 				allowExpressions: true,
-				service: name,
+				service: appname,
 				version: '0.0.1'
 				version: '0.0.1'
 			}
 			}
 		})
 		})
-
-		collectDefaultMetrics({ timeout: 5000, prefix: name + "_" })
+		Metrics.inc("process_startup")
 
 
 	registerDestructor: (func) ->
 	registerDestructor: (func) ->
 		destructors.push func
 		destructors.push func
@@ -44,63 +40,90 @@ module.exports = Metrics =
 			res.end(Register.metrics())
 			res.end(Register.metrics())
 		)
 		)
 
 
-	sanitizeKey: (key) ->
+	buildPromKey: (key = "")->
 		key.replace /[^a-zA-Z0-9]/g, "_"
 		key.replace /[^a-zA-Z0-9]/g, "_"
 
 
 	sanitizeValue: (value) ->
 	sanitizeValue: (value) ->
 		parseFloat(value)
 		parseFloat(value)
 
 
 	set : (key, value, sampleRate = 1)->
 	set : (key, value, sampleRate = 1)->
-		statsd.set buildKey(key), value, sampleRate
-
-	inc : (key, sampleRate = 1)->
-		statsd.increment buildKey(key), sampleRate
-		key = this.sanitizeKey(key)
-		if !counters[key]
-			counters[key] = new prom.Counter({
-		  		name: key,
+		console.log("counts are not currently supported")
+
+	inc : (key, sampleRate = 1, opts = {})->
+		key = Metrics.buildPromKey(key)
+		if !promMetrics[key]?
+			promMetrics[key] = new prom.Counter({
+				name: key,
 				help: key, 
 				help: key, 
-				labelNames: ['name','host']
+				labelNames: ['app','host','status','method']
 			})
 			})
-		counters[key].inc({name: name, host: hostname})
+		opts.app = appname
+		opts.host = hostname
+		promMetrics[key].inc(opts)
+		if process.env['DEBUG_METRICS']
+			console.log("doing inc", key, opts)
 
 
 	count : (key, count, sampleRate = 1)->
 	count : (key, count, sampleRate = 1)->
-		statsd.count buildKey(key), count, sampleRate
-
-	timing: (key, timeSpan, sampleRate)->
-		statsd.timing(buildKey(key), timeSpan, sampleRate)
+		key = Metrics.buildPromKey(key)
+		if !promMetrics[key]?
+			promMetrics[key] = new prom.Counter({
+				name: key,
+				help: key, 
+				labelNames: ['app','host']
+			})
+		promMetrics[key].inc({app: appname, host: hostname}, count)
+		if process.env['DEBUG_METRICS']
+			console.log("doing count/inc", key, opts)
+
+	timing: (key, timeSpan, sampleRate, opts = {})->
+		key = Metrics.buildPromKey("timer_" + key)
+		if !promMetrics[key]?
+			promMetrics[key] = new prom.Summary({
+				name: key,
+				help: key,
+				maxAgeSeconds: 600,
+				ageBuckets: 10,
+				labelNames: ['app', 'path', 'status_code', 'method', 'collection', 'query']
+			})
+		opts.app = appname
+		promMetrics[key].observe(opts, timeSpan)
+		if process.env['DEBUG_METRICS']
+			console.log("doing timing", key, opts)
 
 
 	Timer : class
 	Timer : class
-		constructor :(key, sampleRate = 1)->
+		constructor :(key, sampleRate = 1, opts)->
 			this.start = new Date()
 			this.start = new Date()
+			key = Metrics.buildPromKey(key)
 			this.key = key
 			this.key = key
 			this.sampleRate = sampleRate
 			this.sampleRate = sampleRate
+			this.opts = opts
+
 		done:->
 		done:->
 			timeSpan = new Date - this.start
 			timeSpan = new Date - this.start
-			statsd.timing(buildKey(this.key), timeSpan, this.sampleRate)
+			Metrics.timing(this.key, timeSpan, this.sampleRate, this.opts)
 			return timeSpan
 			return timeSpan
 
 
 	gauge : (key, value, sampleRate = 1)->
 	gauge : (key, value, sampleRate = 1)->
-		statsd.gauge buildKey(key), value, sampleRate
-		key = this.sanitizeKey(key)
-		if !gauges[key]
-			gauges[key] = new prom.Gauge({
-		  		name: key,
+		key = Metrics.buildPromKey(key)
+		if !promMetrics[key]?
+			promMetrics[key] = new prom.Gauge({
+				name: key,
 				help: key, 
 				help: key, 
-				labelNames: ['name','host']
+				labelNames: ['app','host']
 			})
 			})
-		gauges[key].set({name: name, host: hostname},this.sanitizeValue(value))
-
+		promMetrics[key].set({app: appname, host: hostname}, this.sanitizeValue(value))
+		if process.env['DEBUG_METRICS']
+			console.log("doing gauge", key, opts)
+			
 	globalGauge: (key, value, sampleRate = 1)->
 	globalGauge: (key, value, sampleRate = 1)->
-		statsd.gauge buildGlobalKey(key), value, sampleRate
-		key = this.sanitizeKey(key)
-		if !gauges[key]
-			gauges[key] = new prom.Gauge({
-		  		name: key,
+		key = Metrics.buildPromKey(key)
+		if !promMetrics[key]?
+			promMetrics[key] = new prom.Gauge({
+				name: key,
 				help: key, 
 				help: key, 
-				labelNames: ['name','host']
+				labelNames: ['app','host']
 			})
 			})
-		gauges[key].set({name: name},this.sanitizeValue(value))
+		promMetrics[key].set({app: appname},this.sanitizeValue(value))
 
 
 	mongodb: require "./mongodb"
 	mongodb: require "./mongodb"
 	http: require "./http"
 	http: require "./http"
@@ -113,4 +136,3 @@ module.exports = Metrics =
 	close: () ->
 	close: () ->
 		for func in destructors
 		for func in destructors
 			func()
 			func()
-		statsd.close()

+ 1 - 1
libraries/metrics/mongodb.coffee

@@ -34,7 +34,7 @@ module.exports =
 					query = Object.keys(db_command.query).sort().join("_")
 					query = Object.keys(db_command.query).sort().join("_")
 					key += "." + query
 					key += "." + query
 
 
-				timer = new Metrics.Timer(key)
+				timer = new Metrics.Timer("mongo", {collection: collection, query:query})
 				start = new Date()
 				start = new Date()
 				_method.call this, db_command, options, () ->
 				_method.call this, db_command, options, () ->
 					timer.done()
 					timer.done()

+ 5 - 5
libraries/metrics/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "metrics-sharelatex",
   "name": "metrics-sharelatex",
-  "version": "1.9.0",
+  "version": "2.0.7",
   "description": "A drop-in metrics and monitoring module for node.js apps",
   "description": "A drop-in metrics and monitoring module for node.js apps",
   "repository": {
   "repository": {
     "type": "git",
     "type": "git",
@@ -10,7 +10,9 @@
     "coffee-script": "1.6.0",
     "coffee-script": "1.6.0",
     "lynx": "~0.1.1",
     "lynx": "~0.1.1",
     "prom-client": "^11.1.3",
     "prom-client": "^11.1.3",
-    "underscore": "~1.6.0"
+    "underscore": "~1.6.0",
+    "@google-cloud/debug-agent": "^3.0.0",
+    "@google-cloud/trace-agent": "^3.2.0"
   },
   },
   "devDependencies": {
   "devDependencies": {
     "bunyan": "^1.0.0",
     "bunyan": "^1.0.0",
@@ -22,8 +24,6 @@
     "grunt-execute": "^0.2.2",
     "grunt-execute": "^0.2.2",
     "grunt-mocha-test": "^0.11.0",
     "grunt-mocha-test": "^0.11.0",
     "sandboxed-module": "",
     "sandboxed-module": "",
-    "sinon": "",
-    "@google-cloud/debug-agent": "^3.0.0",
-    "@google-cloud/trace-agent": "^3.2.0"
+    "sinon": ""
   }
   }
 }
 }

+ 12 - 4
libraries/metrics/timeAsyncMethod.coffee

@@ -5,9 +5,17 @@ module.exports = (obj, methodName, prefix, logger) ->
 	if typeof obj[methodName] != 'function'
 	if typeof obj[methodName] != 'function'
 		throw new Error("[Metrics] expected object property '#{methodName}' to be a function")
 		throw new Error("[Metrics] expected object property '#{methodName}' to be a function")
 
 
-	realMethod = obj[methodName]
 	key = "#{prefix}.#{methodName}"
 	key = "#{prefix}.#{methodName}"
 
 
+	realMethod = obj[methodName]
+
+	splitPrefix = prefix.split(".")
+	startPrefix = splitPrefix[0]
+
+	if splitPrefix[1]?
+		modifedMethodName = "#{splitPrefix[1]}_#{methodName}"
+	else
+		modifedMethodName = methodName
 	obj[methodName] = (originalArgs...) ->
 	obj[methodName] = (originalArgs...) ->
 
 
 		[firstArgs..., callback] = originalArgs
 		[firstArgs..., callback] = originalArgs
@@ -17,15 +25,15 @@ module.exports = (obj, methodName, prefix, logger) ->
 				logger.log "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback"
 				logger.log "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback"
 			return realMethod.apply this, originalArgs
 			return realMethod.apply this, originalArgs
 
 
-		timer = new metrics.Timer(key)
+		timer = new metrics.Timer(startPrefix, 1, {method: modifedMethodName})
 
 
 		realMethod.call this, firstArgs..., (callbackArgs...) ->
 		realMethod.call this, firstArgs..., (callbackArgs...) ->
 			elapsedTime = timer.done()
 			elapsedTime = timer.done()
 			possibleError = callbackArgs[0]
 			possibleError = callbackArgs[0]
 			if possibleError? 
 			if possibleError? 
-				metrics.inc "#{key}.failure"
+				metrics.inc "#{startPrefix}_result", 1, {status:"failed", method: modifedMethodName}
 			else
 			else
-				metrics.inc "#{key}.success"
+				metrics.inc "#{startPrefix}_result", 1, {status:"success", method: modifedMethodName}
 			if logger?
 			if logger?
 				loggableArgs = {}
 				loggableArgs = {}
 				try
 				try