Skip to content

Commit

Permalink
printStackTrace() was replaced with logging
Browse files Browse the repository at this point in the history
  • Loading branch information
Bohdan-Kim committed May 20, 2024
1 parent fff17ac commit 60776aa
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 50 deletions.
16 changes: 13 additions & 3 deletions lib/src/main/java/growthbook/sdk/java/ConditionEvaluator.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@

import javax.annotation.Nullable;
import java.lang.reflect.Type;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand All @@ -18,6 +24,7 @@
class ConditionEvaluator implements IConditionEvaluator {

private final GrowthBookJsonUtils jsonUtils = GrowthBookJsonUtils.getInstance();
private final Logger logger = Logger.getLogger(ConditionEvaluator.class.getName());

/**
* Evaluate a condition for a set of user attributes based on the provided condition.
Expand Down Expand Up @@ -66,7 +73,10 @@ public Boolean evaluateCondition(String attributesJsonString, String conditionJs

return true;
} catch (RuntimeException e) {
e.printStackTrace();
logger.log(Level.SEVERE,
"Error evaluate condition for attributesJsonString: "
+ attributesJsonString +", and conditionJsonString: "
+ conditionJsonString, e);
return false;
}
}
Expand Down Expand Up @@ -436,7 +446,7 @@ Boolean arePrimitivesEqual(JsonPrimitive a, JsonPrimitive b, DataType dataType)
//
}

System.out.printf("\nUnsupported data type %s", dataType);
logger.log(Level.INFO, "Unsupported data type " + dataType);

return false;
}
Expand Down
7 changes: 6 additions & 1 deletion lib/src/main/java/growthbook/sdk/java/DecryptionUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* INTERNAL: This class is used internally to decrypt an encrypted features response
*/
class DecryptionUtils {
private static final Logger logger = Logger.getLogger(DecryptionUtils.class.getName());


public static class DecryptionException extends Exception {
public DecryptionException(String errorMessage) {
Expand Down Expand Up @@ -65,7 +69,8 @@ public static String decrypt(String payload, String encryptionKey) throws Decryp
| IllegalArgumentException
| BadPaddingException e
) {
e.printStackTrace();
logger.log(Level.SEVERE, "Error during decryption", e);

throw new DecryptionException(e.getMessage());
}
}
Expand Down
11 changes: 8 additions & 3 deletions lib/src/main/java/growthbook/sdk/java/FeatureEvaluator.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* <b>INTERNAL</b>: Implementation of feature evaluation
Expand All @@ -16,6 +18,7 @@ class FeatureEvaluator implements IFeatureEvaluator {
private final GrowthBookJsonUtils jsonUtils = GrowthBookJsonUtils.getInstance();
private final ConditionEvaluator conditionEvaluator = new ConditionEvaluator();
private final ExperimentEvaluator experimentEvaluator = new ExperimentEvaluator();
private final Logger logger = Logger.getAnonymousLogger();

@Override
public <ValueType> FeatureResult<ValueType> evaluateFeature(String key, GBContext context, Class<ValueType> valueTypeClass) throws ClassCastException {
Expand Down Expand Up @@ -65,7 +68,7 @@ public <ValueType> FeatureResult<ValueType> evaluateFeature(String key, GBContex
.build();

if (featureJson == null) {
System.out.println("featureJson is null");
logger.log(Level.CONFIG, "FeatureJson is null for ", key);

// When key exists but there is no value, should be default value with null value
if (featureUsageCallback != null) {
Expand Down Expand Up @@ -107,6 +110,7 @@ public <ValueType> FeatureResult<ValueType> evaluateFeature(String key, GBContex
attributes = new JsonObject();
}
// System.out.printf("\n\nAttributes = %s", attributes);
logger.log(Level.INFO, "Attributes = ", attributes);

// region Rules

Expand Down Expand Up @@ -229,7 +233,7 @@ public <ValueType> FeatureResult<ValueType> evaluateFeature(String key, GBContex
}
return defaultValueFeatureResult;
} catch (Exception e) {
e.printStackTrace();
logger.log(Level.SEVERE, "Error evaluating feature " + key, e);
return emptyFeature;
}
}
Expand Down Expand Up @@ -262,7 +266,8 @@ public <ValueType> FeatureResult<ValueType> evaluateFeature(String key, GBContex

return GrowthBookUtils.getForcedSerializableValueFromUrl(key, url, valueTypeClass, jsonUtils.gson);
} catch (MalformedURLException | ClassCastException e) {
e.printStackTrace();
logger.log(Level.SEVERE, "Error evaluating forced feature "
+ key + " from URL " + urlString, e);
return null;
}
}
Expand Down
9 changes: 6 additions & 3 deletions lib/src/main/java/growthbook/sdk/java/GBContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

/**
* Context object passed into the GrowthBook constructor.
Expand Down Expand Up @@ -57,7 +58,7 @@ public GBContext(
String decrypted = DecryptionUtils.decrypt(featuresJson, encryptionKey);
this.featuresJson = decrypted.trim();
} catch (DecryptionUtils.DecryptionException e) {
e.printStackTrace();
logger.throwing(GBContext.class.getName(), "contractor", e);
}
} else if (featuresJson != null) {
// Use features
Expand All @@ -73,6 +74,8 @@ public GBContext(
this.featureUsageCallback = featureUsageCallback;
}

private static final Logger logger = Logger.getLogger(GBContext.class.getName());

@Nullable
@Getter(AccessLevel.PACKAGE)
private JsonObject features;
Expand Down Expand Up @@ -177,7 +180,7 @@ private static JsonObject transformFeatures(String featuresJsonString) {
try {
return GrowthBookJsonUtils.getInstance().gson.fromJson(featuresJsonString, JsonObject.class);
} catch (Exception e) {
e.printStackTrace();
logger.throwing(GBContext.class.getName(), "transformFeatures", e);
return null;
}
}
Expand All @@ -195,7 +198,7 @@ private static JsonObject transformAttributes(@Nullable String attributesJsonStr

return GrowthBookJsonUtils.getInstance().gson.fromJson(attributesJsonString, JsonObject.class);
} catch (Exception e) {
e.printStackTrace();
logger.throwing(GBContext.class.getName(), "transformAttributes", e);
return new JsonObject();
}
}
Expand Down
63 changes: 36 additions & 27 deletions lib/src/main/java/growthbook/sdk/java/GBFeaturesRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.google.gson.JsonObject;
import lombok.Builder;
import lombok.Getter;
import okhttp3.*;
import okhttp3.OkHttpClient;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import okhttp3.sse.EventSources;
Expand All @@ -16,6 +16,8 @@
import java.util.ArrayList;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* This class can be created with its `builder()` or constructor.
Expand Down Expand Up @@ -54,8 +56,9 @@ public class GBFeaturesRepository implements IGBFeaturesRepository {
private Boolean initialized = false;

private Boolean sseAllowed = false;
@Nullable private Request sseRequest = null;
@Nullable private okhttp3.Request sseRequest = null;
@Nullable private EventSource sseEventSource = null;
private static final Logger logger = Logger.getLogger(GBFeaturesRepository.class.getName());

/**
* Allows you to get the features JSON from the provided {@link GBFeaturesRepository#getFeaturesEndpoint()}.
Expand Down Expand Up @@ -158,23 +161,23 @@ public void clearCallbacks() {
private void enqueueFeatureRefreshRequest() {
GBFeaturesRepository self = this;

Request request = new Request.Builder()
okhttp3.Request request = new okhttp3.Request.Builder()
.url(this.featuresEndpoint)
.build();

this.okHttpClient.newCall(request).enqueue(new Callback() {
this.okHttpClient.newCall(request).enqueue(new okhttp3.Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
public void onFailure(@NotNull okhttp3.Call call, @NotNull IOException e) {
// OkHttp will auto-retry on failure
self.onRefreshFailed(e);
}

@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
public void onResponse(@NotNull okhttp3.Call call, @NotNull okhttp3.Response response) {
try {
self.onSuccess(response);
} catch (FeatureFetchException e) {
e.printStackTrace();
logger.log(Level.SEVERE, "Error refreshing features", e);
}
}
});
Expand All @@ -200,7 +203,10 @@ public void initialize() throws FeatureFetchException {

private void initializeSSE() {
if (!this.sseAllowed) {
System.out.printf("\nFalling back to stale-while-revalidate refresh strategy. 'X-Sse-Support: enabled' not present on resource returned at %s", this.featuresEndpoint);
logger.log(Level.INFO,
"Falling back to stale-while-revalidate refresh strategy. "
+ "'X-Sse-Support: enabled' not present on resource returned at "
+ this.featuresEndpoint);
this.refreshStrategy = FeatureRefreshStrategy.STALE_WHILE_REVALIDATE;
}

Expand All @@ -226,7 +232,7 @@ private void createEventSourceListenerAndStartListening() {
.build();
}

this.sseRequest = new Request.Builder()
this.sseRequest = new okhttp3.Request.Builder()
.url(this.eventsEndpoint)
.header("Accept", "application/json; q=0.5")
.addHeader("Accept", "text/event-stream")
Expand All @@ -246,15 +252,14 @@ public void onFeaturesResponse(String featuresJsonResponse) throws FeatureFetchE
onResponseJson(featuresJsonResponse);
}
}));
this.sseHttpClient.newCall(sseRequest).enqueue(new Callback() {
this.sseHttpClient.newCall(sseRequest).enqueue(new okhttp3.Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
System.out.println("SSE connection failed");
e.printStackTrace();
public void onFailure(@NotNull okhttp3.Call call, @NotNull IOException e) {
logger.log(Level.SEVERE, "SSE connection failed", e);
}

@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
public void onResponse(@NotNull okhttp3.Call call, @NotNull okhttp3.Response response) throws IOException {
// We don't do anything with this response
}
});
Expand Down Expand Up @@ -289,21 +294,21 @@ private Boolean isCacheExpired() {
*/
private void fetchFeatures() throws FeatureFetchException {
if (this.featuresEndpoint == null) {
logger.log(Level.SEVERE, "features endpoint cannot be null");
throw new IllegalArgumentException("features endpoint cannot be null");
}

Request request = new Request.Builder()
okhttp3.Request request = new okhttp3.Request.Builder()
.url(this.featuresEndpoint)
.build();

try (Response response = this.okHttpClient.newCall(request).execute()) {
try (okhttp3.Response response = this.okHttpClient.newCall(request).execute()) {
String sseSupportHeader = response.header("x-sse-support");
this.sseAllowed = Objects.equals(sseSupportHeader, "enabled");

this.onSuccess(response);
} catch (IOException e) {
e.printStackTrace();

logger.log(Level.SEVERE, "Error fetching features", e);
throw new FeatureFetchException(
FeatureFetchException.FeatureFetchErrorCode.UNKNOWN,
e.getMessage()
Expand All @@ -327,6 +332,7 @@ private void onResponseJson(String responseJsonString) throws FeatureFetchExcept
// Use encrypted features at responseBody.encryptedFeatures
JsonElement encryptedFeaturesJsonElement = jsonObject.get("encryptedFeatures");
if (encryptedFeaturesJsonElement == null) {
logger.log(Level.SEVERE, "Configuration Error: encryptionKey provided but endpoint not encrypted");
throw new FeatureFetchException(
FeatureFetchException.FeatureFetchErrorCode.CONFIGURATION_ERROR,
"encryptionKey provided but endpoint not encrypted"
Expand All @@ -339,6 +345,7 @@ private void onResponseJson(String responseJsonString) throws FeatureFetchExcept
// Use unencrypted features at responseBody.features
JsonElement featuresJsonElement = jsonObject.get("features");
if (featuresJsonElement == null) {
logger.log(Level.SEVERE, "Configuration Error: No features found");
throw new FeatureFetchException(
FeatureFetchException.FeatureFetchErrorCode.CONFIGURATION_ERROR,
"No features found"
Expand All @@ -352,8 +359,7 @@ private void onResponseJson(String responseJsonString) throws FeatureFetchExcept

this.onRefreshSuccess(this.featuresJson);
} catch (DecryptionUtils.DecryptionException e) {
e.printStackTrace();

logger.log(Level.SEVERE, "Error fetching features");
throw new FeatureFetchException(
FeatureFetchException.FeatureFetchErrorCode.UNKNOWN,
e.getMessage()
Expand All @@ -377,19 +383,19 @@ private void onRefreshFailed(Throwable throwable) {
* Handles the successful features fetching response
* @param response Successful response
*/
private void onSuccess(Response response) throws FeatureFetchException {
private void onSuccess(okhttp3.Response response) throws FeatureFetchException {
try {
ResponseBody responseBody = response.body();
okhttp3.ResponseBody responseBody = response.body();
if (responseBody == null) {
logger.log(Level.SEVERE, "Feature Fetch Exception Response Body is null");
throw new FeatureFetchException(
FeatureFetchException.FeatureFetchErrorCode.NO_RESPONSE_ERROR
);
}

onResponseJson(responseBody.string());
} catch (IOException e) {
e.printStackTrace();

logger.log(Level.SEVERE, "Error fetching features", e);
throw new FeatureFetchException(
FeatureFetchException.FeatureFetchErrorCode.UNKNOWN,
e.getMessage()
Expand Down Expand Up @@ -424,17 +430,20 @@ public void onEvent(@NotNull EventSource eventSource, @Nullable String id, @Null
try {
handler.onFeaturesResponse(data);
} catch (FeatureFetchException e) {
e.printStackTrace();
logger.log(Level.SEVERE,
"FeatureFetch in SSE connection with EventSource "
+ eventSource + " and with id: "
+ id + " and data: " + data, e);
}
}

@Override
public void onFailure(@NotNull EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
public void onFailure(@NotNull EventSource eventSource, @Nullable Throwable t, @Nullable okhttp3.Response response) {
super.onFailure(eventSource, t, response);
}

@Override
public void onOpen(@NotNull EventSource eventSource, @NotNull Response response) {
public void onOpen(@NotNull EventSource eventSource, @NotNull okhttp3.Response response) {
super.onOpen(eventSource, response);
}
}
Expand Down
Loading

0 comments on commit 60776aa

Please sign in to comment.