Skip to content
Browse files

Refactorings and make the units for the metrics servlet configurable

  • Loading branch information...
1 parent 7f2c2d8 commit 43082b643735dc6bc3fabb830b073c0ccf1df4bb @jeffellis committed Nov 11, 2013
View
2 LICENSE
@@ -187,7 +187,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright 2012 Jeff Ellis
+ Copyright 2013 Jeff Ellis
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
View
2 NOTICE
@@ -1,5 +1,5 @@
Grails Metrics plugin
-Copyright 2010-2012 Coda Hale and Yammer, Inc.
+Copyright 2010-2013 Coda Hale and Yammer, Inc.
This product includes software developed by Coda Hale and Yammer, Inc.
View
4 README.md
@@ -106,11 +106,11 @@ License
-------
This plugin is
- Copyright (c) 2012 Jeff Ellis
+ Copyright (c) 2013 Jeff Ellis
Published under Apache Software License 2.0, see LICENSE
The metrics jars are:
- Copyright (c) 2010-2012 Coda Hale, Yammer.com
+ Copyright (c) 2010-2013 Coda Hale, Yammer.com
Published under Apache Software License 2.0
View
62 YammerMetricsGrailsPlugin.groovy
@@ -1,15 +1,14 @@
-import com.codahale.metrics.MetricRegistry
-import com.codahale.metrics.health.HealthCheckRegistry
-import com.codahale.metrics.servlets.HealthCheckServlet
import com.codahale.metrics.servlets.MetricsServlet
-import org.apache.commons.lang.StringUtils
-import org.grails.plugins.yammermetrics.groovy.HealthCheckServletContextListener
-import org.grails.plugins.yammermetrics.groovy.MetricsServletContextListener
+import grails.util.Holders
+import org.grails.plugins.yammermetrics.groovy.HealthCheckServletContextInitializer
+import org.grails.plugins.yammermetrics.groovy.HealthCheckServletContextInitializer
+import org.grails.plugins.yammermetrics.groovy.MetricsServletContextInitializer
import javax.servlet.ServletContextEvent
+import java.util.concurrent.TimeUnit
/*
- * Copyright 2012 Jeff Ellis
+ * Copyright 2013 Jeff Ellis
*/
class YammerMetricsGrailsPlugin {
@@ -42,15 +41,48 @@ See the source code documentation on Github for more details.
def doWithWebDescriptor = { xml ->
if(application.config.metrics.servletEnabled!=false){
- def count = xml.'servlet'.size()
+ def count
+
+ // It doesn't seem like context-params are where Coda meant for these to be defined based on the
+ // MetricsServlet.ContextListener, but this is where MetricsServlet actually reads them from. Need to
+ // file an issue or at least verify this is what he meant.
+
+ count = xml.'context-param'.size()
+ if(count > 0) {
+
+ def contextParamElement = xml.'context-param'[count - 1]
+
+ def unit = Holders.getConfig().yammermetrics.servlet.rateUnit
+ if(unit instanceof String) {
+ contextParamElement + {
+ 'context-param' {
+ 'param-name'(MetricsServlet.RATE_UNIT)
+ 'param-value'(unit)
+ }
+ }
+ }
+
+ unit = Holders.getConfig().yammermetrics.servlet.durationUnit
+ if(unit instanceof String) {
+ contextParamElement + {
+ 'context-param' {
+ 'param-name'(MetricsServlet.DURATION_UNIT)
+ 'param-value'(unit)
+ }
+ }
+ }
+
+ }
+
+ count = xml.'servlet'.size()
if(count > 0) {
def servletElement = xml.'servlet'[count - 1]
servletElement + {
'servlet' {
'servlet-name'("YammerMetrics")
- 'servlet-class'("org.grails.plugins.yammermetrics.reporting.GrailsAdminServlet")
+ 'servlet-class'("com.codahale.metrics.servlets.AdminServlet")
}
}
println "***\nYammerMetrics servlet injected into web.xml"
@@ -88,16 +120,16 @@ See the source code documentation on Github for more details.
def doWithApplicationContext = { applicationContext ->
// Create registries for HealthChecks and Metrics here, and stuff them into the servlet context. Don't
- // wait for the regular listener lifecycle because that happens after application BootStrap.groovy.
+ // wait for the regular listener lifecycle because that happens after application BootStrap.groovy. Since
+ // we're doing this here, there is no need to wire them as real listeners.
ServletContextEvent event = new ServletContextEvent(applicationContext.servletContext)
- HealthCheckServletContextListener healthCheckServletContextListener = new HealthCheckServletContextListener()
- healthCheckServletContextListener.contextInitialized(event)
+ HealthCheckServletContextInitializer healthCheckServletContextInitializer = new HealthCheckServletContextInitializer()
+ healthCheckServletContextInitializer.contextInitialized(event)
- MetricsServletContextListener metricsServletContextListener = new MetricsServletContextListener()
- metricsServletContextListener.contextInitialized(event)
+ MetricsServletContextInitializer metricsServletContextInitializer = new MetricsServletContextInitializer()
+ metricsServletContextInitializer.contextInitialized(event)
- println "Registries in servletContext"
}
def onChange = { event ->
View
7 example-app/grails-app/conf/Config.groovy
@@ -1,3 +1,5 @@
+import java.util.concurrent.TimeUnit
+
// locations to search for config files that get merged into the main config;
// config files can be ConfigSlurper scripts, Java properties files, or classes
// in the classpath in ConfigSlurper format
@@ -90,5 +92,6 @@ log4j = {
'net.sf.ehcache.hibernate'
}
-println "Setting metrics.servletUrlPattern"
-//metrics.servletUrlPattern = "/groovy-metrics/*"
+//metrics.servletUrlPattern = "/groovy-metrics/*"
+yammermetrics.servlet.rateUnit = "days"
+yammermetrics.servlet.durationUnit = "hours"
View
15 example-app/grails-app/controllers/metricstest/PegController.groovy
@@ -1,6 +1,8 @@
package metricstest
+import com.codahale.metrics.Counter
import com.codahale.metrics.Gauge
+import com.codahale.metrics.Histogram
import org.grails.plugins.yammermetrics.groovy.Metered
import org.grails.plugins.yammermetrics.groovy.Metrics
import org.grails.plugins.yammermetrics.groovy.Timed
@@ -16,6 +18,9 @@ class PegController {
}
}
+ Counter counter = Metrics.newCounter("count.something")
+ Histogram histogram = Metrics.newHistogram("sample.histogram")
+
PegController() {
Metrics.newGauge("DepthGauge", new DepthGauge())
}
@@ -31,4 +36,14 @@ class PegController {
render( contentType: "text/plain", text: "Timed!" )
}
+ def counter() {
+ counter.inc()
+ render( contentType: "text/plain", text: "Counted!" )
+ }
+
+ def histogram() {
+ histogram.update(1)
+ render( contentType: "text/plain", text: "Histogram updated!" )
+ }
+
}
View
2 grails-app/conf/Config.groovy
@@ -1,3 +1,5 @@
+import java.util.concurrent.TimeUnit
+
// configuration for plugin testing - will not be included in the plugin zip
log4j = {
View
2 .../HealthCheckServletContextListener.groovy → ...althCheckServletContextInitializer.groovy
@@ -3,7 +3,7 @@ package org.grails.plugins.yammermetrics.groovy
import com.codahale.metrics.health.HealthCheckRegistry
import com.codahale.metrics.servlets.HealthCheckServlet
-class HealthCheckServletContextListener extends HealthCheckServlet.ContextListener {
+class HealthCheckServletContextInitializer extends HealthCheckServlet.ContextListener {
public final HealthCheckRegistry healthCheckRegistry = new HealthCheckRegistry()
View
15 src/groovy/org/grails/plugins/yammermetrics/groovy/HealthChecks.groovy
@@ -9,11 +9,20 @@ class HealthChecks {
private static final HealthCheckRegistry builtInRegistry = new HealthCheckRegistry()
- static void register( String name, HealthCheck healthCheck) {
+ static void register( String name, HealthCheck healthCheck ) {
+ HealthCheckRegistry registry = getRegistry()
+ registry.register(name, healthCheck)
+ }
+
+ static HealthCheckRegistry getRegistry() {
+ // Use the registry from the servletContext if one has been configured in doWithApplicationContext (i.e., the
+ // normal runtime case for apps using the plugin) or fall back to the built in one otherwise (e.g., unit tests
+ // which happen to touch instrumented classes)
+
HealthCheckRegistry registry = Holders?.servletContext?.getAttribute(HealthCheckServlet.HEALTH_CHECK_REGISTRY)
- if(!registry) {
+ if (!registry) {
registry = builtInRegistry
}
- registry.register(name, healthCheck)
+ return registry
}
}
View
84 src/groovy/org/grails/plugins/yammermetrics/groovy/Metrics.groovy
@@ -4,72 +4,98 @@ import com.codahale.metrics.Counter
import com.codahale.metrics.Histogram
import com.codahale.metrics.JmxReporter
import com.codahale.metrics.Meter
+import com.codahale.metrics.Metric
+import com.codahale.metrics.MetricFilter
import com.codahale.metrics.MetricRegistry
import com.codahale.metrics.Reservoir
import com.codahale.metrics.servlets.MetricsServlet
import com.codahale.metrics.Gauge
import grails.util.Holders
import org.codehaus.groovy.reflection.ReflectionUtils
+import java.util.concurrent.TimeUnit
+
class Metrics {
private static final MetricRegistry builtInRegistry = new MetricRegistry()
- // ignore org.springsource.loaded.ri.ReflectiveInterceptor when not running as a war, and ignore this class for convenience
- static final List<String> extraIgnoredPackages = ["org.springsource.loaded.ri", "org.grails.plugins.yammermetrics.groovy"]
+ // ignore org.springsource.loaded.ri.ReflectiveInterceptor when not running as a war, and ignore this class for convenience
+ static final List<String> extraIgnoredPackages = ["org.springsource.loaded.ri", "org.grails.plugins.yammermetrics.groovy"]
- private Metrics() { super() }
+ private static String expandNameToIncludeCallingClass(String metricName) {
+ Class callingClass = ReflectionUtils.getCallingClass(0, extraIgnoredPackages)
+ return MetricRegistry.name(callingClass, metricName)
+ }
- static Gauge newGauge(String gaugeName, Gauge gauge){
- String metricName = MetricRegistry.name(ReflectionUtils.getCallingClass(0, extraIgnoredPackages), gaugeName)
- def metric = registry.getGauges().get(metricName)
- if(!metric) {
- metric = registry.register(metricName, gauge)
+ static Metric getOrAdd(String name, Metric metricToAdd) {
+ String metricName = expandNameToIncludeCallingClass(name)
+ Metric metric = registry.getMetrics().get(metricName)
+ if (!metric) {
+ metric = registry.register(metricName, metricToAdd)
}
return metric
}
- static Counter newCounter(String counterName){
- return registry.counter(MetricRegistry.name(ReflectionUtils.getCallingClass(0, extraIgnoredPackages), counterName))
+ static Gauge newGauge(String name, Gauge gauge) {
+ return getOrAdd(name, gauge) as Gauge
}
- static Histogram newHistogram(String name){
- return registry.histogram(MetricRegistry.name(ReflectionUtils.getCallingClass(0, extraIgnoredPackages), name))
+ static Counter newCounter(String name) {
+ String metricName = expandNameToIncludeCallingClass(name)
+ return registry.counter(metricName)
}
- static Histogram newHistogram(String name, Reservoir reservoir){
- String metricName = MetricRegistry.name(ReflectionUtils.getCallingClass(0, extraIgnoredPackages), name)
- def metric = registry.getHistograms().get(metricName)
- if(!metric) {
- Histogram histogram = new Histogram(reservoir)
- metric = registry.register(metricName, histogram)
- }
- return metric
+ static Histogram newHistogram(String name) {
+ String metricName = expandNameToIncludeCallingClass(name)
+ return registry.histogram(metricName)
+ }
+
+ static Histogram newHistogram(String name, Reservoir reservoir) {
+ Histogram histogram = new Histogram(reservoir)
+ return getOrAdd(name, histogram) as Histogram
}
- static Meter newMeter(String meterName){
- return registry.meter(MetricRegistry.name(ReflectionUtils.getCallingClass(0, extraIgnoredPackages), meterName))
+ static Meter newMeter(String name) {
+ String metricName = expandNameToIncludeCallingClass(name)
+ return registry.meter(metricName)
}
- static com.codahale.metrics.Timer newTimer(String timerName){
- return registry.timer(MetricRegistry.name(ReflectionUtils.getCallingClass(0, extraIgnoredPackages), timerName))
+ static com.codahale.metrics.Timer newTimer(String name) {
+ String metricName = expandNameToIncludeCallingClass(name)
+ return registry.timer(metricName)
}
- static com.codahale.metrics.Timer newTimer(Class owner, String timerName){
- return registry.timer(MetricRegistry.name(owner, timerName))
+ static com.codahale.metrics.Timer newTimer(Class owner, String name) {
+ String metricName = MetricRegistry.name(owner, name)
+ return registry.timer(metricName)
}
static MetricRegistry getRegistry() {
+
+ // Use the registry from the servletContext if one has been configured in doWithApplicationContext (i.e., the
+ // normal runtime case for apps using the plugin) or fall back to the built in one otherwise (e.g., unit tests
+ // which happen to touch instrumented classes)
+
MetricRegistry metricRegistry = Holders?.servletContext?.getAttribute(MetricsServlet.METRICS_REGISTRY) as MetricRegistry
- if(!metricRegistry) {
+ if (!metricRegistry) {
metricRegistry = builtInRegistry
}
return metricRegistry
}
- static JmxReporter startJmxReporter() {
- final JmxReporter reporter = JmxReporter.forRegistry(Metrics.getRegistry()).build();
+ static JmxReporter startJmxReporter(TimeUnit rateUnit = TimeUnit.SECONDS, TimeUnit durationUnit = TimeUnit.MILLISECONDS) {
+ final JmxReporter reporter = JmxReporter
+ .forRegistry(registry)
+ .convertRatesTo(rateUnit)
+ .convertDurationsTo(durationUnit)
+ .build();
reporter.start();
return reporter
}
+
+ static removeAll() {
+ registry.removeMatching(MetricFilter.ALL)
+ }
+
+ private Metrics() {}
}
View
36 src/groovy/org/grails/plugins/yammermetrics/groovy/MetricsServletContextInitializer.groovy
@@ -0,0 +1,36 @@
+package org.grails.plugins.yammermetrics.groovy
+
+import com.codahale.metrics.MetricRegistry
+import com.codahale.metrics.servlets.MetricsServlet
+import grails.util.Holders
+
+import java.util.concurrent.TimeUnit
+
+class MetricsServletContextInitializer extends MetricsServlet.ContextListener {
+
+ public final MetricRegistry metricRegistry = new MetricRegistry()
+
+ @Override
+ protected MetricRegistry getMetricRegistry() {
+ return metricRegistry
+ }
+
+ @Override
+ protected TimeUnit getRateUnit() {
+ return getUnitFromConfig("rateUnit")
+ }
+
+ @Override
+ protected TimeUnit getDurationUnit() {
+ return getUnitFromConfig("durationUnit")
+ }
+
+ private TimeUnit getUnitFromConfig(String propertyName) {
+ def unit = Holders.config.yammermetrics.servlet[propertyName]
+ if (unit instanceof String) {
+ return TimeUnit.valueOf(unit.toUpperCase(Locale.US))
+ }
+ return null
+ }
+
+}
View
14 src/groovy/org/grails/plugins/yammermetrics/groovy/MetricsServletContextListener.groovy
@@ -1,14 +0,0 @@
-package org.grails.plugins.yammermetrics.groovy
-
-import com.codahale.metrics.MetricRegistry
-import com.codahale.metrics.servlets.MetricsServlet
-
-class MetricsServletContextListener extends MetricsServlet.ContextListener {
-
- public final MetricRegistry metricRegistry = new MetricRegistry()
-
- @Override
- protected MetricRegistry getMetricRegistry() {
- return metricRegistry
- }
-}
View
3 src/groovy/org/grails/plugins/yammermetrics/groovy/Timer.groovy
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 Jeff Ellis
+ * Copyright 2013 Jeff Ellis
*/
package org.grails.plugins.yammermetrics.groovy
@@ -12,7 +12,6 @@ class Timer {
String owner
String name
- private static final log = LogFactory.getLog(Timer)
private ownerLog
Timer(Class<?> owner, String name) {
View
4 src/groovy/org/grails/plugins/yammermetrics/groovy/ast/YMeteredASTTransformation.groovy
@@ -25,10 +25,10 @@ public class YMeteredASTTransformation implements ASTTransformation {
AnnotationNode annotationNode = nodes[0]
MethodNode methodNode = nodes[1]
String meterName = ensureMeterConfigured(annotationNode, methodNode.declaringClass, methodNode)
- makeMeteredMethod(meterName, methodNode.declaringClass, methodNode)
+ makeMeteredMethod(meterName, methodNode)
}
- private void makeMeteredMethod(String meterName, ClassNode classNode, MethodNode methodNode){
+ private void makeMeteredMethod(String meterName, MethodNode methodNode){
try {
def meterCall = new ExpressionStatement (new MethodCallExpression(new VariableExpression(meterName), "mark", new ArgumentListExpression() ) )
//Add meter call
View
16 src/groovy/org/grails/plugins/yammermetrics/reporting/GrailsAdminServlet.groovy
@@ -1,16 +0,0 @@
-package org.grails.plugins.yammermetrics.reporting
-
-import com.codahale.metrics.servlets.AdminServlet
-import com.codahale.metrics.servlets.MetricsServlet
-import com.codahale.metrics.servlets.PingServlet
-import com.codahale.metrics.servlets.ThreadDumpServlet
-
-class GrailsAdminServlet extends AdminServlet {
-
- GrailsAdminServlet() {
- super()
-// super(new GrailsHealthCheckServlet(), new MetricsServlet(), new PingServlet(),
-// new ThreadDumpServlet(), AdminServlet.DEFAULT_HEALTHCHECK_URI, AdminServlet.DEFAULT_METRICS_URI,
-// AdminServlet.DEFAULT_PING_URI, AdminServlet.DEFAULT_THREADS_URI);
- }
-}
View
14 src/groovy/org/grails/plugins/yammermetrics/reporting/GrailsHealthCheckServlet.groovy
@@ -1,14 +0,0 @@
-package org.grails.plugins.yammermetrics.reporting
-
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
-import javax.servlet.ServletException
-import com.codahale.metrics.servlets.HealthCheckServlet
-
-class GrailsHealthCheckServlet extends HealthCheckServlet {
-
- void doGet( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException {
- super.doGet( req, new GrailsRoutablePrintWriterWorkaroundResponse( resp ) )
- }
-
-}
View
29 ...grails/plugins/yammermetrics/reporting/GrailsRoutablePrintWriterWorkaroundResponse.groovy
@@ -1,29 +0,0 @@
-package org.grails.plugins.yammermetrics.reporting
-
-import javax.servlet.http.HttpServletResponse
-import org.codehaus.groovy.grails.web.sitemesh.GrailsRoutablePrintWriter
-
-class GrailsRoutablePrintWriterWorkaroundResponse implements HttpServletResponse {
-
- @Delegate
- HttpServletResponse realResponse
-
- GrailsRoutablePrintWriterWorkaroundResponse(HttpServletResponse httpServletResponse) {
- realResponse = httpServletResponse
- }
-
- @Override
- PrintWriter getWriter() {
- //
- // GrailsRoutablePrintWriter has a bug where if you call format before any other methods that
- // call getDestination(), no output will be produced in the response. HealthCheckServlet does this
- // when run under grails. This workaround class makes sure that getDestination() is called by calling getOut()
- // when obtaining the PrintWriter.
- //
- PrintWriter writer = realResponse.getWriter()
- if( writer instanceof GrailsRoutablePrintWriter ) {
- writer.getOut()
- }
- return writer
- }
-}
View
10 test/unit/com/codahale/metrics/groovy/MeterTest.groovy
@@ -1,16 +1,8 @@
package com.codahale.metrics.groovy
import com.codahale.metrics.Meter
-import com.codahale.metrics.MetricFilter
-import com.codahale.metrics.MetricRegistry
import org.grails.plugins.yammermetrics.groovy.Metrics
-/**
- * User: GavinHogan@gmail.com
- * Date: 5/23/12
- * Time: 4:37 PM
- */
-
class MeterTest extends GroovyTestCase {
SampleObject sample
@@ -19,7 +11,7 @@ class MeterTest extends GroovyTestCase {
}
void tearDown() {
- Metrics.registry.removeMatching(MetricFilter.ALL)
+ Metrics.removeAll()
}
void testAddingMeterField(){
View
9 test/unit/com/codahale/metrics/groovy/TimedTest.groovy
@@ -1,15 +1,8 @@
package com.codahale.metrics.groovy
-import com.codahale.metrics.MetricFilter
-import com.codahale.metrics.MetricRegistry
import com.codahale.metrics.Timer
import org.grails.plugins.yammermetrics.groovy.Metrics
-/**
- * User: GavinHogan@gmail.com
- * Date: 5/23/12
- * Time: 2:37 PM
- */
class TimedTest extends GroovyTestCase {
SampleObject sample
@@ -18,7 +11,7 @@ class TimedTest extends GroovyTestCase {
}
void tearDown() {
- Metrics.registry.removeMatching(MetricFilter.ALL)
+ Metrics.removeAll()
}
void testAddingTimerField(){

0 comments on commit 43082b6

Please sign in to comment.
Something went wrong with that request. Please try again.