commit
760d261275
@ -0,0 +1,18 @@ |
|||||||
|
|
||||||
|
The Libresonic framework contains a convenient class (called MetricsManager) to add inner metrics that constructs in real time some performance indicators. |
||||||
|
|
||||||
|
The use of MetricsManager is illustrated in the org.libresonic.player.filter.MetricsFilter class. |
||||||
|
|
||||||
|
The MetricsFilter adds a metric based on the time spent by each /main.view HTTP request. This is interesting as the main.view request is invoqued when something is displayed in the main Libresonic web frame. |
||||||
|
|
||||||
|
By default, the MetricsManager is deactivated; it does nothing. |
||||||
|
It can be activated only by adding the following line inside the livresonic.properties configuration file : |
||||||
|
|
||||||
|
``` |
||||||
|
Metrics= |
||||||
|
``` |
||||||
|
|
||||||
|
Once the MetricsManager as been activated this way, each metric can be inspected using a jmx console like VisualVM. |
||||||
|
Each metric is registered as a MBean as shown below. |
||||||
|
|
||||||
|
![](metrics-visualvm-screenshot.png) |
After Width: | Height: | Size: 27 KiB |
@ -0,0 +1,37 @@ |
|||||||
|
package org.libresonic.player.filter; |
||||||
|
|
||||||
|
import org.libresonic.player.monitor.MetricsManager; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
|
||||||
|
import javax.servlet.*; |
||||||
|
import javax.servlet.http.HttpServletRequest; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by remi on 12/01/17. |
||||||
|
*/ |
||||||
|
public class MetricsFilter implements Filter { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private MetricsManager metricsManager; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void init(FilterConfig filterConfig) throws ServletException { |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { |
||||||
|
HttpServletRequest httpServletRequest = (HttpServletRequest)request; |
||||||
|
|
||||||
|
String timerName = httpServletRequest.getRequestURI(); |
||||||
|
// Add a metric that measures the time spent for each http request for the /main.view url.
|
||||||
|
try (MetricsManager.Timer t = metricsManager.condition(timerName.contains("main.view")).timer(this,timerName)) { |
||||||
|
chain.doFilter(request, response); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void destroy() { |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,163 @@ |
|||||||
|
package org.libresonic.player.monitor; |
||||||
|
|
||||||
|
import com.codahale.metrics.JmxReporter; |
||||||
|
import com.codahale.metrics.MetricRegistry; |
||||||
|
import org.libresonic.player.service.ApacheCommonsConfigurationService; |
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by remi on 17/01/17. |
||||||
|
*/ |
||||||
|
public class MetricsManager { |
||||||
|
|
||||||
|
private ApacheCommonsConfigurationService configurationService; |
||||||
|
|
||||||
|
// Main metrics registry
|
||||||
|
private static final MetricRegistry metrics = new MetricRegistry(); |
||||||
|
|
||||||
|
private static Boolean metricsActivatedByConfiguration = null; |
||||||
|
private static Object _lock = new Object(); |
||||||
|
|
||||||
|
// Potential metrics reporters
|
||||||
|
private static JmxReporter reporter; |
||||||
|
|
||||||
|
private void configureMetricsActivation() { |
||||||
|
if (configurationService.containsKey("Metrics")) { |
||||||
|
metricsActivatedByConfiguration = Boolean.TRUE; |
||||||
|
|
||||||
|
// Start a Metrics JMX reporter
|
||||||
|
reporter = JmxReporter.forRegistry(metrics) |
||||||
|
.convertRatesTo(TimeUnit.SECONDS.SECONDS) |
||||||
|
.convertDurationsTo(TimeUnit.MILLISECONDS) |
||||||
|
.build(); |
||||||
|
reporter.start(); |
||||||
|
} else { |
||||||
|
metricsActivatedByConfiguration = Boolean.FALSE; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean metricsActivatedByConfiguration() { |
||||||
|
if (metricsActivatedByConfiguration == null) { |
||||||
|
synchronized (_lock) { |
||||||
|
if (metricsActivatedByConfiguration == null) { |
||||||
|
configureMetricsActivation(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return metricsActivatedByConfiguration.booleanValue(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a {@link Timer} whose name is based on a class name and a |
||||||
|
* qualified name. |
||||||
|
* @param clazz |
||||||
|
* @param name |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Timer timer(Class clazz, String name) { |
||||||
|
if (metricsActivatedByConfiguration()) { |
||||||
|
return new TimerBuilder().timer(clazz, name); |
||||||
|
} else { |
||||||
|
return nullTimerSingleton; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a {@link Timer} whose name is based on an object's class name and a |
||||||
|
* qualified name. |
||||||
|
* @param ref |
||||||
|
* @param name |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Timer timer(Object ref, String name) { |
||||||
|
return timer(ref.getClass(),name); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Initiate a {@link TimerBuilder} using a condition. |
||||||
|
* If the condition is false, a void {@link Timer} will finally be built thus |
||||||
|
* no timer will be registered in the Metrics registry. |
||||||
|
* |
||||||
|
* @param ifTrue |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public TimerBuilder condition(boolean ifTrue) { |
||||||
|
if (metricsActivatedByConfiguration()) { |
||||||
|
if (ifTrue == false) { |
||||||
|
return conditionFalseTimerBuilderSingleton; |
||||||
|
} |
||||||
|
return new TimerBuilder(); |
||||||
|
} else { |
||||||
|
return nullTimerBuilderSingleton; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void setConfigurationService(ApacheCommonsConfigurationService configurationService) { |
||||||
|
this.configurationService = configurationService; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* A class that builds a {@link Timer} |
||||||
|
*/ |
||||||
|
public static class TimerBuilder { |
||||||
|
|
||||||
|
public Timer timer(Class clazz, String name) { |
||||||
|
com.codahale.metrics.Timer t = metrics.timer(MetricRegistry.name(clazz,name)); |
||||||
|
com.codahale.metrics.Timer.Context tContext = t.time(); |
||||||
|
return new Timer(tContext); |
||||||
|
} |
||||||
|
|
||||||
|
public Timer timer(Object ref, String name) { |
||||||
|
return timer(ref.getClass(),name); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* A class that holds a Metrics timer context implementing {@link AutoCloseable} |
||||||
|
* thus it can be used in a try-with-resources statement. |
||||||
|
*/ |
||||||
|
public static class Timer implements AutoCloseable { |
||||||
|
|
||||||
|
private com.codahale.metrics.Timer.Context timerContext; |
||||||
|
|
||||||
|
protected Timer(com.codahale.metrics.Timer.Context timerContext) { |
||||||
|
this.timerContext = timerContext; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void close() { |
||||||
|
timerContext.stop(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
// Convenient singletons to avoid creating useless objects instances
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
private static final NullTimer nullTimerSingleton = new NullTimer(null); |
||||||
|
private static final NullTimerBuilder conditionFalseTimerBuilderSingleton = new NullTimerBuilder(); |
||||||
|
private static final NullTimerBuilder nullTimerBuilderSingleton = new NullTimerBuilder(); |
||||||
|
|
||||||
|
private static class NullTimer extends Timer { |
||||||
|
|
||||||
|
protected NullTimer(com.codahale.metrics.Timer.Context timerContext) { |
||||||
|
super(timerContext); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void close() { |
||||||
|
// Does nothing
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static class NullTimerBuilder extends TimerBuilder { |
||||||
|
@Override |
||||||
|
public Timer timer(Class clazz, String name) { |
||||||
|
return nullTimerSingleton; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue