Skip to content

Commit

Permalink
Implement client registration and metrics.
Browse files Browse the repository at this point in the history
Adds implementation where the client register at startup
and sends metrics to the server regulary.

implements #3
  • Loading branch information
ivaosthu committed Nov 9, 2016
1 parent 4752fa2 commit ef2cbcf
Show file tree
Hide file tree
Showing 26 changed files with 949 additions and 101 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@ Spring or Guice to manage this.

You create a new instance with the following command:
```java

UnleashConfig unleashConfig = new UnleashConfig.Builder()
.appName("java-test")
.instanceId("instance x")
.unleashAPI("http://unleash.herokuapp.com")
.build();
URI unleashServer = URI.create("http://unleash.herokuapp.com/features")

Unleash unleash = new DefaultUnleash(unleashServer);
```

Expand Down
45 changes: 32 additions & 13 deletions src/main/java/no/finn/unleash/DefaultUnleash.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,48 @@
package no.finn.unleash;

import java.net.URI;
import java.util.HashMap;
import java.util.Map;

import no.finn.unleash.metric.UnleashMetricService;
import no.finn.unleash.metric.UnleashMetricServiceImpl;
import no.finn.unleash.repository.FeatureToggleRepository;
import no.finn.unleash.repository.ToggleBackupHandlerFile;
import no.finn.unleash.repository.HttpToggleFetcher;
import no.finn.unleash.repository.ToggleRepository;
import no.finn.unleash.strategy.DefaultStrategy;
import no.finn.unleash.strategy.Strategy;
import no.finn.unleash.strategy.UnknownStrategy;
import no.finn.unleash.util.UnleashConfig;
import no.finn.unleash.util.UnleashScheduledExecutor;
import no.finn.unleash.util.UnleashScheduledExecutorImpl;

public final class DefaultUnleash implements Unleash {
private static final DefaultStrategy DEFAULT_STRATEGY = new DefaultStrategy();
private static final UnknownStrategy UNKNOWN_STRATEGY = new UnknownStrategy();
private static final UnleashScheduledExecutor unleashScheduledExecutor = new UnleashScheduledExecutorImpl();

private final UnleashMetricService metricService;
private final ToggleRepository toggleRepository;
private final Map<String, Strategy> strategyMap;

public DefaultUnleash(URI unleashServer, Strategy... strategies) {
this(new FeatureToggleRepository(
new HttpToggleFetcher(unleashServer),
new ToggleBackupHandlerFile()),
strategies);

private static FeatureToggleRepository defaultToggleRepository(UnleashConfig unleashConfig) {
return new FeatureToggleRepository(
unleashConfig,
unleashScheduledExecutor,
new HttpToggleFetcher(unleashConfig),
new ToggleBackupHandlerFile());
}

public DefaultUnleash(ToggleRepository toggleRepository, Strategy... strategies) {
public DefaultUnleash(UnleashConfig unleashConfig, Strategy... strategies) {
this(unleashConfig, defaultToggleRepository(unleashConfig), strategies);
}

public DefaultUnleash(UnleashConfig unleashConfig, ToggleRepository toggleRepository, Strategy... strategies) {
this.toggleRepository = toggleRepository;
this.strategyMap = buildStrategyMap(strategies);
this.metricService = new UnleashMetricServiceImpl(unleashConfig, unleashScheduledExecutor);
metricService.register(strategyMap.keySet());
}

@Override
Expand All @@ -37,18 +52,22 @@ public boolean isEnabled(final String toggleName) {

@Override
public boolean isEnabled(final String toggleName, final boolean defaultSetting) {
boolean enabled = false;
FeatureToggle featureToggle = toggleRepository.getToggle(toggleName);

if (featureToggle == null) {
return defaultSetting;
enabled = defaultSetting;
} else if(!featureToggle.isEnabled()) {
return false;
enabled = false;
} else {
enabled = featureToggle.getStrategies().stream()
.filter(as -> getStrategy(as.getName()).isEnabled(as.getParameters()))
.findFirst()
.isPresent();
}

return featureToggle.getStrategies().stream()
.filter(as -> getStrategy(as.getName()).isEnabled(as.getParameters()))
.findFirst()
.isPresent();
metricService.count(toggleName, enabled);
return enabled;
}

private Map<String, Strategy> buildStrategyMap(Strategy[] strategies) {
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/no/finn/unleash/metric/ClientMetrics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package no.finn.unleash.metric;

import no.finn.unleash.util.UnleashConfig;

class ClientMetrics {

private final String appName;
private final String instanceId;
private final MetricsBucket bucket;

ClientMetrics(UnleashConfig config, MetricsBucket bucket) {
this.appName = config.getAppName();
this.instanceId = config.getInstanceId();
this.bucket = bucket;
}

public String getAppName() {
return appName;
}

public String getInstanceId() {
return instanceId;
}

public MetricsBucket getBucket() {
return bucket;
}
}
42 changes: 42 additions & 0 deletions src/main/java/no/finn/unleash/metric/ClientRegistration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package no.finn.unleash.metric;

import no.finn.unleash.util.UnleashConfig;

import java.time.LocalDateTime;
import java.util.Set;

class ClientRegistration {
private final String appName;
private final String instanceId;
private final Set<String> strategies;
private final LocalDateTime started;
private final long interval;

ClientRegistration(UnleashConfig config, LocalDateTime started, Set<String> strategies) {
this.appName = config.getAppName();
this.instanceId = config.getInstanceId();
this.started = started;
this.strategies = strategies;
this.interval = config.getSendMetricsInterval();
}

public String getAppName() {
return appName;
}

public String getInstanceId() {
return instanceId;
}

public Set<String> getStrategies() {
return strategies;
}

public LocalDateTime getStarted() {
return started;
}

public long getInterval() {
return interval;
}
}
43 changes: 43 additions & 0 deletions src/main/java/no/finn/unleash/metric/MetricsBucket.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package no.finn.unleash.metric;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.Map;

class MetricsBucket {
private final Map<String, ToggleCount> toggles;
private final LocalDateTime start;
private LocalDateTime stop;

MetricsBucket() {
this.start = LocalDateTime.now(ZoneId.of("UTC"));
this.toggles = new HashMap<>();
}

void registerCount(String toggleName, boolean active) {
if(toggles.containsKey(toggleName)) {
toggles.get(toggleName).register(active);
} else {
ToggleCount counter = new ToggleCount();
counter.register(active);
toggles.put(toggleName, counter);
}
}

void end() {
this.stop = LocalDateTime.now(ZoneId.of("UTC"));
}

public Map<String, ToggleCount> getToggles() {
return toggles;
}

public LocalDateTime getStart() {
return start;
}

public LocalDateTime getStop() {
return stop;
}
}
27 changes: 27 additions & 0 deletions src/main/java/no/finn/unleash/metric/ToggleCount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package no.finn.unleash.metric;

class ToggleCount {
private long yes;
private long no;

public ToggleCount() {
this.yes = 0;
this.no = 0;
}

public void register(boolean active) {
if(active) {
yes++;
} else {
no++;
}
}

public long getYes() {
return yes;
}

public long getNo() {
return no;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package no.finn.unleash.metric;

import java.util.Set;

public interface UnleashMetricService {
void register(Set<String> strategies);
void count(String toggleName, boolean active);
}
55 changes: 55 additions & 0 deletions src/main/java/no/finn/unleash/metric/UnleashMetricServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package no.finn.unleash.metric;

import no.finn.unleash.util.UnleashConfig;
import no.finn.unleash.util.UnleashScheduledExecutor;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Set;

public class UnleashMetricServiceImpl implements UnleashMetricService {
private final LocalDateTime started;
private final UnleashConfig unleashConfig;
private final long metricsInterval;
private final UnleashMetricsSender unleashMetricsSender;

//mutable
private MetricsBucket currentMetricsBucket;

public UnleashMetricServiceImpl(UnleashConfig unleashConfig, UnleashScheduledExecutor executor) {
this(unleashConfig, new UnleashMetricsSender(unleashConfig), executor);
}

public UnleashMetricServiceImpl(UnleashConfig unleashConfig,
UnleashMetricsSender unleashMetricsSender,
UnleashScheduledExecutor executor) {
this.currentMetricsBucket = new MetricsBucket();
this.started = LocalDateTime.now(ZoneId.of("UTC"));
this.unleashConfig = unleashConfig;
this.metricsInterval = unleashConfig.getSendMetricsInterval();
this.unleashMetricsSender = unleashMetricsSender;

executor.setInterval(sendMetrics(), metricsInterval, metricsInterval);
}

@Override
public void register(Set<String> strategies) {
ClientRegistration registration = new ClientRegistration(unleashConfig, started, strategies);
unleashMetricsSender.registerClient(registration);
}

@Override
public void count(String toggleName, boolean active) {
currentMetricsBucket.registerCount(toggleName, active);
}

private Runnable sendMetrics() {
return () -> {
MetricsBucket metricsBucket = this.currentMetricsBucket;
this.currentMetricsBucket = new MetricsBucket();
metricsBucket.end();
ClientMetrics metrics = new ClientMetrics(unleashConfig, metricsBucket);
unleashMetricsSender.sendMetrics(metrics);
};
}
}

0 comments on commit ef2cbcf

Please sign in to comment.