adaptive-monitoring-framework
Changes
app-example/pom.xml 2(+1 -1)
tigris/pom.xml 6(+3 -3)
tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/configuration/annotation/TigrisConfiguration.java 2(+1 -1)
tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/monitoring/aspects/TigrisCoordinator.java 27(+12 -15)
Details
app-example/pom.xml 2(+1 -1)
diff --git a/app-example/pom.xml b/app-example/pom.xml
index ef57119..e08c131 100644
--- a/app-example/pom.xml
+++ b/app-example/pom.xml
@@ -219,7 +219,7 @@
<dependency>
<groupId>br.ufrgs.inf.prosoft</groupId>
<artifactId>tigris</artifactId>
- <version>0.10.0-SNAPSHOT</version>
+ <version>0.11.0-SNAPSHOT</version>
</dependency>
</dependencies>
diff --git a/app-example/src/main/resources/logback.xml b/app-example/src/main/resources/logback.xml
index 3f01712..b2ab98a 100644
--- a/app-example/src/main/resources/logback.xml
+++ b/app-example/src/main/resources/logback.xml
@@ -7,14 +7,15 @@
<resetJUL>true</resetJUL>
</contextListener>
- <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
- <pattern>%-5level %logger{0} - %msg%n</pattern>
- </encoder>
- </appender>
+<!-- <appender name="console" class="ch.qos.logback.core.ConsoleAppender">-->
+<!-- <encoder>-->
+<!-- <pattern>%-5level %logger{0} - %msg%n</pattern>-->
+<!-- </encoder>-->
+<!-- </appender>-->
<logger name="org.hibernate" level="OFF"/>
<logger name="org.springframework.samples.petclinic" level="DEBUG"/>
+ <logger name="br.ufrgs.inf.prosoft.tigris" level="DEBUG"/>
<root level="info">
<appender-ref ref="console"/>
tigris/pom.xml 6(+3 -3)
diff --git a/tigris/pom.xml b/tigris/pom.xml
index 23b475d..a972e98 100644
--- a/tigris/pom.xml
+++ b/tigris/pom.xml
@@ -6,7 +6,7 @@
<groupId>br.ufrgs.inf.prosoft</groupId>
<artifactId>tigris</artifactId>
- <version>0.10.0-SNAPSHOT</version>
+ <version>0.11.0-SNAPSHOT</version>
<properties>
<aspectj.version>1.8.9</aspectj.version>
@@ -159,14 +159,14 @@
<version>3.3.1</version>
</dependency>
+ <!-- In order to use the library below, this should be run the first time locally: -->
+ <!-- mvn install:install-file -Dfile=lib\bullwinkle.jar -DgroupId=ca.uqac.lif -DartifactId=bullwinkle -Dversion=1.4.5 -Dpackaging=jar-->
<dependency>
<groupId>ca.uqac.lif</groupId>
<artifactId>bullwinkle</artifactId>
<version>1.4.5</version>
</dependency>
-<!-- mvn install:install-file -Dfile=lib\bullwinkle.jar -DgroupId=ca.uqac.lif -DartifactId=bullwinkle -Dversion=1.4.5 -Dpackaging=jar-->
-
</dependencies>
<build>
diff --git a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/configuration/annotation/TigrisConfiguration.java b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/configuration/annotation/TigrisConfiguration.java
index 31c7e28..c59e982 100644
--- a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/configuration/annotation/TigrisConfiguration.java
+++ b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/configuration/annotation/TigrisConfiguration.java
@@ -45,5 +45,5 @@ public @interface TigrisConfiguration {
*
* @return the int
*/
- int cycleTimeInSeconds() default 3600; //3600 seconds = 1h
+ long cycleTimeInMilliseconds() default 3600000; //3600000 milliseconds = 1h
}
diff --git a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/metrics/StaticMetrics.java b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/metrics/StaticMetrics.java
index 1750b42..222afac 100644
--- a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/metrics/StaticMetrics.java
+++ b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/metrics/StaticMetrics.java
@@ -1,6 +1,9 @@
package br.ufrgs.inf.prosoft.tigris.metrics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
@@ -12,6 +15,8 @@ import java.util.Map;
*/
public class StaticMetrics {
+ static Logger logger = LoggerFactory.getLogger(StaticMetrics.class);
+
private Map<String, StaticMetric> metrics;
/**
@@ -53,7 +58,7 @@ public class StaticMetrics {
metrics.put(str[1], new StaticMetric(Long.valueOf(str[2]), Long.valueOf(str[3]), Long.valueOf(str[4])));
}
} catch (IOException ex) {
- throw new RuntimeException(ex);
+ logger.warn("Not able to open file {} with static metrics. Do not use these metrics for filtering.", filename);
}
}
}
diff --git a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/monitoring/aspects/TigrisCoordinator.java b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/monitoring/aspects/TigrisCoordinator.java
index 9716a08..e388f8f 100644
--- a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/monitoring/aspects/TigrisCoordinator.java
+++ b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/monitoring/aspects/TigrisCoordinator.java
@@ -25,7 +25,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
-import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -93,7 +92,8 @@ public class TigrisCoordinator implements Runnable {
deniedPattern = Pattern.compile(componentScanConfig.denied());
logger.info("@TigrisConfiguration will trace and cache methods into {} and deny {} package.", allowedPattern.pattern(), deniedPattern.pattern());
- sampling = new Sampling(tigrisConfiguration.samplingPercentage(), tigrisConfiguration.cycleTimeInSeconds());
+ sampling = new Sampling(tigrisConfiguration.samplingPercentage(), tigrisConfiguration.cycleTimeInMilliseconds());
+ //TODO when to run it?
samplingAdaptationExecutor.scheduleWithFixedDelay(
sampling, 120000, 450000, TimeUnit.MILLISECONDS);
@@ -124,13 +124,11 @@ public class TigrisCoordinator implements Runnable {
}
try {
-
customMonitoringClass = ConfigurationUtils.getAvailableCustomMonitoringClass();
if (customMonitoringClass != null) {
customMonitoring = (CustomMonitoring) customMonitoringClass.newInstance();
+ customMonitoring.initialize(repository);
}
-
- customMonitoring.initialize(repository);
} catch (ConfigurationException e) {
logger.info("AdaptiveCaching not found, disabling...");
} catch (IllegalAccessException e) {
@@ -143,13 +141,14 @@ public class TigrisCoordinator implements Runnable {
public boolean isAllowed(ProceedingJoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
return
- isEnabled()
- && !signature.getName().contains("br.ufrgs.inf.prosoft")
- && allowedPattern.matcher(signature.getMethod().getDeclaringClass().getPackage().getName()).matches()
- && !deniedPattern.matcher(signature.getMethod().getDeclaringClass().getPackage().getName()).matches();
+ isEnabled()
+ && !signature.getName().contains("br.ufrgs.inf.prosoft")
+ && allowedPattern.matcher(signature.getMethod().getDeclaringClass().getPackage().getName()).matches()
+ && !deniedPattern.matcher(signature.getMethod().getDeclaringClass().getPackage().getName()).matches();
}
public Object process(ProceedingJoinPoint joinPoint) throws Throwable {
+ long monitoringStartTime = currentTimeMillis();
String signature = joinPoint.getSignature().toString();
boolean detailedTrace = (!coarseMonitoringEnabled ||
(coarseMonitoringEnabled && allowedFineGrained
@@ -195,17 +194,14 @@ public class TigrisCoordinator implements Runnable {
}
//trace only allowed by lightweight metrics
- logger.debug("Is coarse monitoring enable? {}", coarseMonitoringEnabled);
- logger.debug("Is {} in the allowed list? {}", signature, detailedTrace);
- boolean shouldSample = sampling.simpleSamplingDecision();
- logger.debug("Should sample it? {} ", shouldSample);
+// boolean shouldSample = sampling.simpleSamplingDecision();
+ boolean shouldSample = sampling.samplingDecision(granularity);
if (coarseMonitoringEnabled
&& detailedTrace
&& shouldSample) {
logger.debug("New trace: " + signature);
- //we do not cache null returns, but we trace them
- //maybe the method can sometimes return null... so there is not verification here
+ //we do trace null returns - maybe the method can sometimes return null... so there is not verification here
LogTrace logTrace = new LogTrace();
logTrace.setStartTime(startTime);
logTrace.setEndTime(endTime);
@@ -216,6 +212,7 @@ public class TigrisCoordinator implements Runnable {
try {
repository.save(logTrace);
logger.debug("New trace entry: " + logTrace);
+ sampling.addSampledItem(granularity, currentTimeMillis() - monitoringStartTime);
} catch (Exception e) {
logger.debug("Couldn't trace " + signature + " due to: " + e.getMessage());
}
diff --git a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/Apdex.java b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/Apdex.java
new file mode 100644
index 0000000..fc10a8f
--- /dev/null
+++ b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/Apdex.java
@@ -0,0 +1,26 @@
+package br.ufrgs.inf.prosoft.tigris.sampling;
+
+public class Apdex {
+
+ private long satisfied;
+ private long tolerated;
+ private long n;
+
+ public Apdex(long satisfied, long tolerated, long n) {
+ this.satisfied = satisfied;
+ this.tolerated = tolerated;
+ this.n = n;
+ }
+
+ public long getSatisfied() {
+ return satisfied;
+ }
+
+ public long getTolerated() {
+ return tolerated;
+ }
+
+ public long getN() {
+ return n;
+ }
+}
diff --git a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/PerformanceBaselineDataSet.java b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/PerformanceBaselineDataSet.java
index a5492e6..f0029df 100644
--- a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/PerformanceBaselineDataSet.java
+++ b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/PerformanceBaselineDataSet.java
@@ -1,14 +1,16 @@
package br.ufrgs.inf.prosoft.tigris.sampling;
+import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
-import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
public class PerformanceBaselineDataSet {
- private Map<Granularity, SummaryStatistics> granularityBaseline = new HashMap<>();
+ private Map<Granularity, SummaryStatistics> granularityBaseline = new ConcurrentHashMap<>();
+ private SummaryStatistics overallBaseline = new SummaryStatistics();
private long n;
public void addItem(Granularity item, long executionTime) {
@@ -19,6 +21,57 @@ public class PerformanceBaselineDataSet {
statistics.addValue(executionTime);
granularityBaseline.put(item, statistics);
n++;
+
+ overallBaseline.addValue(executionTime);
+ }
+
+ public Apdex getApdexResultsPerEvent(Map<Granularity, DescriptiveStatistics> sampledDataSet){
+ long satisfied = 0, tolerated = 0, n = 0;
+ for (Granularity granularity : sampledDataSet.keySet()){
+ SummaryStatistics stats = granularityBaseline.get(granularity);
+ double meanPlusStd = stats.getMean() + stats.getStandardDeviation();
+ for (double value: sampledDataSet.get(granularity).getValues()) {
+ if (value < meanPlusStd){
+ satisfied++;
+ continue;
+ }
+ if (value > meanPlusStd &&
+ value < stats.getMean() + (2 * stats.getStandardDeviation())) {
+ tolerated++;
+ continue;
+ }
+ n++;
+ }
+ }
+ return new Apdex(satisfied, tolerated, n);
+ }
+
+ public Apdex getApdexResults(Map<Granularity, DescriptiveStatistics> sampledDataSet){
+ long satisfied = 0, tolerated = 0, n = 0;
+ for (Granularity granularity : sampledDataSet.keySet()){
+ double meanPlusStd = getOverallAvg() + getOverallStd();
+ for (double value: sampledDataSet.get(granularity).getValues()) {
+ if (value < meanPlusStd){
+ satisfied++;
+ continue;
+ }
+ if (value > meanPlusStd &&
+ value < getOverallAvg() + (2 * getOverallStd())) {
+ tolerated++;
+ continue;
+ }
+ n++;
+ }
+ }
+ return new Apdex(satisfied, tolerated, n);
+ }
+
+ public double getOverallAvg() {
+ return overallBaseline.getMean();
+ }
+
+ public double getOverallStd() {
+ return overallBaseline.getStandardDeviation();
}
public long getTotalItems(){
diff --git a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/Sampling.java b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/Sampling.java
index 1c4795a..25ee90a 100644
--- a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/Sampling.java
+++ b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/Sampling.java
@@ -3,11 +3,14 @@ package br.ufrgs.inf.prosoft.tigris.sampling;
import org.apache.commons.collections4.queue.CircularFifoQueue;
import org.apache.commons.math3.distribution.BinomialDistribution;
import org.apache.commons.math3.ml.neuralnet.sofm.util.ExponentialDecayFunction;
+import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import org.apache.commons.math3.stat.inference.TestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Map;
import java.util.Queue;
+import java.util.concurrent.ConcurrentHashMap;
/**
* The type Sampling decision.
@@ -16,11 +19,13 @@ public class Sampling implements Runnable {
private boolean samplingEnabled = true;
private boolean performanceBaselineEnabled = false;
- private double samplingRate = 0.5; // in percentage, 0 to 1
+ private double samplingRate; // in percentage, 0 to 1
private FrequencyDataSet population = new FrequencyDataSet(), sample = new FrequencyDataSet();
private PerformanceBaselineDataSet performanceBaselineDataSet = new PerformanceBaselineDataSet();
+ private Map<Granularity, DescriptiveStatistics> sampledDataSet = new ConcurrentHashMap<>();
private Queue<PerformanceBaselineDataSet> lastFourPerformanceBaselineDataSets = new CircularFifoQueue<>(4);
private ExponentialDecayFunction decayingPrecision;
+ private long startTime;
Logger logger = LoggerFactory.getLogger(Sampling.class);
@@ -31,10 +36,10 @@ public class Sampling implements Runnable {
*/
private double z = 1.96, p = 0.5, e = 0.05;
- public Sampling(double initialSamplingRate, int cycleLengthInSeconds) {
+ public Sampling(double initialSamplingRate, long cycleLengthInMilliseconds) {
samplingRate = initialSamplingRate;
- //3600 seconds = 1h
- decayingPrecision = new ExponentialDecayFunction(100, 0.01, cycleLengthInSeconds);
+ decayingPrecision = new ExponentialDecayFunction(1, 0.00001, cycleLengthInMilliseconds);
+ startMonitoringCycle();
}
public boolean simpleSamplingDecision(){
@@ -44,13 +49,13 @@ public class Sampling implements Runnable {
public boolean samplingDecision(Granularity granularity) {
population.addItem(granularity);
- if(performanceBaselineEnabled) {
+ if (performanceBaselineEnabled) {
return false;
}
boolean decision = samplingEnabled
&& simpleSamplingDecision() // sampling rate evaluation
- && population.getProportion(granularity) > sample.getProportion(granularity); // sample has not enough items of that granularity compared to the population
+ && population.getProportion(granularity) >= sample.getProportion(granularity); // sample has not enough items of that granularity compared to the population
if (decision)
sample.addItem(granularity);
@@ -63,74 +68,84 @@ public class Sampling implements Runnable {
}
public boolean isReady() {
+ double decayingConfidenceFactor = decayingConfidenceFactor(getMonitoringCycleTime());
return
// margin of error is lower than threshold
- getSampleSizeErrorMargin() < e
+ getSampleSizeErrorMargin(z * decayingConfidenceFactor) < e
// the sample has the min sample size based on the population
- && sample.getTotalItems() > getMinimumSampleSize()
+ && sample.getTotalItems() > getMinimumSampleSize(z * decayingConfidenceFactor)
// proportion test
- && isSameProportion()
+ && isSameProportion(decayingConfidenceFactor)
// t-test
- && tTestEvaluation();
+ && tTestEvaluation(decayingConfidenceFactor);
}
- private double decayingConfidence(int timeInSeconds){
- return decayingPrecision.value(timeInSeconds);
+ private double decayingConfidenceFactor(long timeInMilliseconds){
+ return decayingPrecision.value(timeInMilliseconds);
}
- private boolean tTestEvaluation() {
+ private boolean tTestEvaluation(double decayingConfidenceFactor) {
//To test the (one-sample t-test - compare with the population mean)
// hypothesis sample mean = mu at the 95% level
return TestUtils.tTest(population.getAsDescriptiveStatistics().getMean(),
sample.getAsDescriptiveStatistics(),
- 0.05);
+ 0.05 * decayingConfidenceFactor);
}
//sample proportion is the same as population
- public boolean isSameProportion() {
- return population.getGranularities().stream().allMatch(granularity -> population.getProportion(granularity) == sample.getProportion(granularity));
+ public boolean isSameProportion(double decayingConfidenceFactor) {
+ return population.getGranularities().stream().allMatch(
+ granularity -> {
+ double popProportion = population.getProportion(granularity);
+ double samProportion = sample.getProportion(granularity);
+ double error = popProportion - (popProportion * decayingConfidenceFactor);
+
+ return samProportion <= popProportion + error &&
+ samProportion >= popProportion - error;
+ });
}
/**
* @return the minimum sample size for the population
*/
public long getMinimumSampleSize() {
- long n_inf = (long) ((Math.pow(z, 2) * p * (1 - p)) / Math.pow(e, 2));
- return n_inf / (1 + ((n_inf - 1) / population.getTotalItems()));
+ return getMinimumSampleSize(population.getTotalItems());
}
public long getMinimumSampleSize(long n) {
- long n_inf = (long) ((Math.pow(z, 2) * p * (1 - p)) / Math.pow(e, 2));
- return n_inf / (1 + ((n_inf - 1) / n));
- }
-
- public double getSampleSizeErrorMargin() {
- double e_n_inf = Math.sqrt((Math.pow(z, 2) * p * (1 - p)) / sample.getTotalItems());
- return e_n_inf * Math.sqrt((population.getTotalItems() - sample.getTotalItems()) / (population.getTotalItems() - 1));
+ return getMinimumSampleSize(n, z);
}
- public void disable() {
- samplingEnabled = false;
+ public long getMinimumSampleSize(double precision) {
+ return getMinimumSampleSize(population.getTotalItems(), precision);
}
- public void enable() {
- samplingEnabled = true;
+ public long getMinimumSampleSize(long n, double precision) {
+ long n_inf = (long) ((Math.pow(precision, 2) * p * (1 - p)) / Math.pow(e, 2));
+ return n_inf / (1 + ((n_inf - 1) / n));
}
- public boolean isSamplingEnabled() {
- return samplingEnabled;
+ public double getSampleSizeErrorMargin() {
+ return getSampleSizeErrorMargin(z);
}
- public double getSamplingRate() {
- return samplingRate;
+ public double getSampleSizeErrorMargin(double precision) {
+ double e_n_inf = Math.sqrt((Math.pow(precision, 2) * p * (1 - p)) / sample.getTotalItems());
+ return e_n_inf * Math.sqrt((population.getTotalItems() - sample.getTotalItems()) / (population.getTotalItems() - 1));
}
public void startMonitoringCycle() {
+ startTime = System.currentTimeMillis();
+ }
+ public long getMonitoringCycleTime(){
+ return (System.currentTimeMillis() - startTime);
}
public void endMonitoringCycle() {
-
+ this.sampledDataSet = new ConcurrentHashMap<>();
+ releaseForAnalysis();
+ startMonitoringCycle();
}
public boolean shouldCollectPerformanceBaseline() {
@@ -138,21 +153,34 @@ public class Sampling implements Runnable {
}
public void adaptSamplingRate() {
- //TODO
+ Apdex apdex = this.performanceBaselineDataSet.getApdexResults(this.sampledDataSet);
+ double impact = 1 - ((apdex.getSatisfied() + 0.5 * apdex.getTolerated()) / apdex.getN());
+ if (impact == 0) {
+ logger.info("No monitoring impact detected, increasing the sampling rate...");
+ //if no impact, increase by 1%
+ samplingRate += 0.01;
+ }
+ if (impact > 0.1) {
+ logger.info("Monitoring impact detected, decreasing the sampling rate by {}...", impact);
+ //reduce by the amount of overhead
+ samplingRate = samplingRate - impact;
+ }
+
+ //otherwise stays the same - not necessary here
+ //if (impact > 0 && impact <= 0.1) { }
}
@Override
public void run() {
- logger.info("Running sampling adaptation.");
+ //TODO this is supposed to run from time to time based on triggers? Or every new trace collected?
if (isReady()) {
logger.info("Sample is ready, releasing for analysis and resetting...");
- //TODO
- releaseForAnalysis();
- reset();
+ endMonitoringCycle();
return;
}
if (shouldCollectPerformanceBaseline()) {
+ logger.info("Enabling performance baseline...");
enablePerformanceBaseline();
return;
}
@@ -166,22 +194,41 @@ public class Sampling implements Runnable {
public void releaseForAnalysis() {
}
- public void reset() {
- }
-
public boolean isPerformanceBaselineEnabled() {
return performanceBaselineEnabled;
}
+ private Long minimumSampleSize;
public void addPerformanceBaselineItem(Granularity granularity, long executionTime) {
+ if (minimumSampleSize == null) {
+ minimumSampleSize = getMinimumSampleSize(this.population.getTotalItems());
+ }
+
+ logger.info("Collecting performance baseline for the next {} traces...",
+ minimumSampleSize - this.performanceBaselineDataSet.getTotalItems());
this.performanceBaselineDataSet.addItem(granularity, executionTime);
- if(this.performanceBaselineDataSet.getTotalItems() >=
- getMinimumSampleSize(this.performanceBaselineDataSet.getTotalItems())) {
- enable();
+ if(this.performanceBaselineDataSet.getTotalItems() > minimumSampleSize) {
+ //got enough traces for PB
+ logger.info("Finished to collect the performance baseline, enabling sampling again...");
+ samplingEnabled = true;
+ minimumSampleSize = null;
this.performanceBaselineEnabled = false;
lastFourPerformanceBaselineDataSets.add(this.performanceBaselineDataSet);
this.performanceBaselineDataSet = new PerformanceBaselineDataSet();
}
}
+
+ public void addSampledItem(Granularity granularity, long executionTime) {
+ DescriptiveStatistics statistics = new DescriptiveStatistics();
+ if (sampledDataSet.containsKey(granularity)){
+ statistics = sampledDataSet.get(granularity);
+ }
+ statistics.addValue(executionTime);
+ sampledDataSet.put(granularity, statistics);
+
+
+ //TODO run it every new trace collected?
+ run();
+ }
}
diff --git a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/utils/ConfigurationUtils.java b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/utils/ConfigurationUtils.java
index 2322644..0834b9f 100644
--- a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/utils/ConfigurationUtils.java
+++ b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/utils/ConfigurationUtils.java
@@ -33,6 +33,8 @@ public final class ConfigurationUtils {
reflections.getSubTypesOf(CustomMonitoring.class);
if (configurations.size() > 1)
throw new ConfigurationException("Multiple implementations of CustomMonitoring.class.");
+ if (configurations.size() == 0)
+ return null;
return configurations.iterator().next();
}
diff --git a/tigris/src/test/java/br/ufrgs/inf/prosoft/tigris/SamplingTest.java b/tigris/src/test/java/br/ufrgs/inf/prosoft/tigris/SamplingTest.java
new file mode 100644
index 0000000..26ee2ce
--- /dev/null
+++ b/tigris/src/test/java/br/ufrgs/inf/prosoft/tigris/SamplingTest.java
@@ -0,0 +1,16 @@
+package br.ufrgs.inf.prosoft.tigris;
+
+import br.ufrgs.inf.prosoft.tigris.sampling.Granularity;
+import br.ufrgs.inf.prosoft.tigris.sampling.GranularityType;
+import br.ufrgs.inf.prosoft.tigris.sampling.Sampling;
+import org.junit.Test;
+
+public class SamplingTest {
+
+ @Test
+ public void samplingDecision(){
+ Sampling sampling = new Sampling(0.5, 100);
+ sampling.samplingDecision(new Granularity(GranularityType.METHOD, "function"));
+ sampling.samplingDecision(new Granularity(GranularityType.METHOD, "function"));
+ }
+}