Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collect and send custom attributes for capture feature #89

Merged
merged 34 commits into from
Jul 25, 2024

Conversation

satsukies
Copy link
Member

@satsukies satsukies commented Jul 22, 2024

I added an implementation that will be used to enhance the capture function provided after the next version.

  • Users can add attributes freely and their values via CustomAttributes class .
  • Attributes are divided into two groups. BuildEnvironment or RuntimeExtra.
    • DeployGate instance keeps CustomAttriutes of each groups.
  • The attributes are sent automatically to DeployGate by SDK when the capture is created.
    • When SDK received ACTION_COLLECT_DEVICE_STATES event, SDK will write values via content provider.

@satsukies satsukies self-assigned this Jul 22, 2024
@@ -1390,4 +1401,192 @@ public static String getDistributionUserName() {

return sInstance.mDistributionUserName;
}

public static boolean putBuildEnvironmentValue(String key, String value) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to add comments each public method.

@satsukies
Copy link
Member Author

@jmatsu
Could you check if my implementation plan has any problems or concerns before finish my work?
Thank you.

Copy link
Contributor

@jmatsu jmatsu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approach basically looks good. Please check my comments.

@satsukies satsukies changed the title WIP: Collect custom attributes for capture feature Collect and send custom attributes for capture feature Jul 22, 2024
@satsukies satsukies marked this pull request as ready for review July 22, 2024 09:54
@satsukies satsukies requested a review from jmatsu July 22, 2024 09:54
@satsukies
Copy link
Member Author

satsukies commented Jul 22, 2024

@jmatsu
Thank you for your feedback.
I made some changes after your feedback.

  1. Added CustomAttributes class for keeping custom attributes.
  2. Added to checking key and value following the feature specs.
  3. Added tests.
  4. Added implementation of writing custom attributes to content provider using received URI.

Could you please re-review this PR? Thank you.

Copy link
Contributor

@jmatsu jmatsu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approach looks basically good. Please check my comments.

@jmatsu
Copy link
Contributor

jmatsu commented Jul 22, 2024

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the same test located in sdk module to checking provide same methods each modules.

@satsukies
Copy link
Member Author

@jmatsu
Thanks for your careful feedback!
Please re-review some fixes and whole codes.

@satsukies satsukies requested a review from jmatsu July 23, 2024 01:58
Copy link
Contributor

@jmatsu jmatsu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please be careful for synchronization, sdk-mock interfaces and AIDL operations.

Comment on lines 142 to 144
if (sBuildEnvironment != null && !sBuildEnvironment.isEmpty()) {
cv.put(DeployGateEvent.ATTRIBUTE_KEY_BUILD_ENVIRONMENT, sBuildEnvironment.toJsonString());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for modifying these codes and I noticed a new thing. This code can be decomposed to like the following.

// Be not synchornized by `sLock`
if (sBuildEnvironment != null) {
  // These multiple operations are not synchornized by `ConcurrentHashMap`
  if (sBuildEnvironment.isEmpty()) {
     doSomething(sBuildEnvironment.toJsonString())
  }
}

Synchronization issues are here so we need to fix it. And also, isEmpty check can be shrunken cuz it's just a JSON.

String buildEnvironmentJson = getBuildEnvironment().toJsonString();

if (!buildEnvironmentJson.equals("{}") {
  cv.put(DeployGateEvent.ATTRIBUTE_KEY_BUILD_ENVIRONMENT, buildEnvironmentJson);
}

cv.put(DeployGateEvent.ATTRIBUTE_KEY_EVENT_AT, System.currentTimeMillis());

ContentResolver cr = mApplicationContext.getContentResolver();
cr.insert(targetUri, cv);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please introduce try-catch and suppress the error for safer operations.

@@ -179,4 +179,12 @@ public static void composeComment(String defaultComment) {
public static String getDistributionUserName() {
return null;
}

public static CustomAttributes getBuildEnvironment() {
return null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't make here null. It's always non-null on sdk so this code means sdk-mock is unreliable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment remind me of you said "must be always non-null for friendly interfaces" in previous review.
I'll fix it.

}

String toJsonString() {
return null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't make here null. It's always non-null on sdk so this code means sdk-mock is unreliable.

@@ -1390,4 +1412,34 @@ public static String getDistributionUserName() {

return sInstance.mDistributionUserName;
}

public static CustomAttributes getBuildEnvironment() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

private static CustomAttributes sRuntimeExtra = null;
private static CustomAttributes sBuildEnvironment;
private static CustomAttributes sRuntimeExtra;
private static CustomAttributes sSdkRuntimeExtra;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This attrs will be used to collect data for valuable on the debugging.
It is always empty at this point.

@@ -15,7 +13,7 @@ public final class CustomAttributes {
private static final Pattern VALID_KEY_PATTERN = Pattern.compile("^[a-z][_a-z0-9]{2,31}$");
private static final int MAX_VALUE_LENGTH = 64;

private final ConcurrentHashMap<String, Object> attributes;
final ConcurrentHashMap<String, Object> attributes;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Visibility changed.
we can use attributes from Deploygate class directly, but users cannot use.

synchronized (getRuntimeExtra().attributes) {
if (!getRuntimeExtra().attributes.isEmpty()) {
for (Map.Entry<String, Object> attr : getRuntimeExtra().attributes.entrySet()) {
String userKey = String.format("%s.%s", mHostApp.packageName, attr.getKey());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to append prefix to attribute keys created by user.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't add the extra time-consuming processing. If we append the prefix in CustomAttributes, doesn't it work?

} catch (Exception e) {
Truth.assertWithMessage("Failed to parse JSON").fail();
}
public void size() {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add new testcase for checking behavior size() and isEmpty() methods.

@satsukies
Copy link
Member Author

@jmatsu
Thanks for your review!
So sorry to request reviews many times, could you please re-review?

@satsukies satsukies requested a review from jmatsu July 23, 2024 13:07
Copy link
Contributor

@jmatsu jmatsu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please be careful about the device resources.

@@ -0,0 +1 @@
../../../../../../../sdk/src/test/java/com/deploygate/sdk/CustomAttributesInterfaceTest.java
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -5,6 +5,8 @@

public class DeployGate {

private static final CustomAttributes sAttributes = new CustomAttributes();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

synchronized (getRuntimeExtra().attributes) {
if (!getRuntimeExtra().attributes.isEmpty()) {
for (Map.Entry<String, Object> attr : getRuntimeExtra().attributes.entrySet()) {
String userKey = String.format("%s.%s", mHostApp.packageName, attr.getKey());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't add the extra time-consuming processing. If we append the prefix in CustomAttributes, doesn't it work?

@satsukies
Copy link
Member Author

We discussed in-person to plan for how to fix current codes.
Following the discussion, I worked on belows.

  • Separating params of sending attributes from SDK by 3 groups. BuildEnvironment, RuntimeExtras and SdkDeviceStatus.
  • Improve implementation of CustomAttributes to be thread-safe.

@jmatsu
Could you please check my codes? Thanks.

Copy link
Contributor

@jmatsu jmatsu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost LGTM. Could you please add one important testcase?


@Test
public void getBuildEnvironment() {
Truth.assertThat(DeployGate.getBuildEnvironment()).isNotNull();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

}

@Test()
public void not_exceed_max_size_multi_thread() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome 👏

import java.util.concurrent.Executors;

@RunWith(AndroidJUnit4.class)
public class CustomAttributesTest {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@satsukies Could you please add a testcase for getJSONString if it's empty? It must return {}.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry.
I added testcase for getJSONString method in 063fc76 .

Logger.w(TAG, "Attributes already reached max size. Ignored: " + key);
return false;
}
} catch (JSONException e) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

@jmatsu jmatsu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great. Thank you for the tough work.

@satsukies
Copy link
Member Author

Thanks for comment.
I added important testcase for getJSONString method.

@satsukies
Copy link
Member Author

Thank you for the tough work.

You too, thank you for your review many times and careful feedback.

@satsukies satsukies merged commit 0bf65d8 into master Jul 25, 2024
6 checks passed
@satsukies satsukies deleted the feat/collect-device-stats branch July 25, 2024 04:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants