Skip to content

Commit

Permalink
ref: Get payload length in captureEnvelope on Android (#208)
Browse files Browse the repository at this point in the history
Gets rid of the extra call across the native bridge that we used to have when we package the payload on the JS side with getStringBytesLength.

Also splits the iOS call into 2 parameters rather than a single object.
  • Loading branch information
jennmueng committed Mar 18, 2021
1 parent 83b5bf3 commit 8bd1235
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 48 deletions.
60 changes: 43 additions & 17 deletions src/android/io/sentry/SentryCordova.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,21 @@ public boolean execute(String action, JSONArray args, final CallbackContext call

break;
case "captureEnvelope":
String envelope = args.getString(0);
String headerString = null;
String payloadString = null;
String payloadType = "event";

captureEnvelope(envelope, callbackContext);
if (!args.isNull(0)) {
headerString = args.getString(0);
}
if (!args.isNull(1)) {
payloadString = args.getString(1);
}
if (!args.isNull(2)) {
payloadType = args.getString(2);
}

captureEnvelope(headerString, payloadString, payloadType, callbackContext);

break;
case "setUser":
Expand All @@ -89,14 +101,6 @@ public boolean execute(String action, JSONArray args, final CallbackContext call
break;
case "clearBreadcrumbs":
clearBreadcrumbs(callbackContext);
break;
case "getStringBytesLength":
String payload = args.getString(0);

int length = getStringBytesLength(payload);

callbackContext.sendPluginResult(new PluginResult(Status.OK, length));

break;
case "setTag":
String tagKey = args.getString(0);
Expand Down Expand Up @@ -214,12 +218,36 @@ private void startWithOptions(final JSONObject jsonOptions, final CallbackContex
}
}

private void captureEnvelope(String envelope, final CallbackContext callbackContext) {
if (envelope == null || envelope.equals("")) {
private void captureEnvelope(String headerString, String payloadString, String payloadType, final CallbackContext callbackContext) {
if (headerString == null || headerString.equals("") || payloadString == null || payloadString.equals("")) {
logger.log(Level.WARNING, "Received an envelope that was null or empty");
} else if (writeEnvelope(envelope)) {
callbackContext.sendPluginResult(new PluginResult(Status.OK, true));
return;
} else {
try {
int payloadLength = payloadString.getBytes("UTF-8").length;

JSONObject item = new JSONObject();
item.put("content_type", "application/json");
item.put("length", payloadLength);
item.put("type", payloadType);
String itemString = item.toString();

String envelopeString = new StringBuilder()
.append(headerString)
.append("\n")
.append(itemString)
.append("\n")
.append(payloadString)
.toString();

if (writeEnvelope(envelopeString)) {
logger.info("Envelope write successful");

callbackContext.sendPluginResult(new PluginResult(Status.OK, true));
return;
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error deserializing envelope from native bridge", e);
}
}

callbackContext.sendPluginResult(new PluginResult(Status.ERROR, false));
Expand Down Expand Up @@ -368,8 +396,6 @@ public void setContext(String contextKey, JSONObject jsonContext, final Callback
callbackContext.sendPluginResult(new PluginResult(Status.OK, true));
}

private int getStringBytesLength(String payload) throws UnsupportedEncodingException { return payload.getBytes("UTF-8").length; }

private SentryLevel getSentryLevelFromString(String level) {
switch (level) {
case "fatal":
Expand Down
20 changes: 11 additions & 9 deletions src/ios/SentryCordova.m
Original file line number Diff line number Diff line change
Expand Up @@ -76,28 +76,30 @@ - (void)setReleaseVersionDist:(SentryEvent *)event {
}

- (void)captureEnvelope:(CDVInvokedUrlCommand *)command {
NSDictionary *envelopeDict = [command.arguments objectAtIndex:0];
NSDictionary *headerDict = [command.arguments objectAtIndex:0];
NSDictionary *payloadDict = [command.arguments objectAtIndex:1];

CDVPluginResult *result =
[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:YES];

if ([NSJSONSerialization isValidJSONObject:envelopeDict]) {
SentrySdkInfo *sdkInfo =
[[SentrySdkInfo alloc] initWithDict:envelopeDict[@"header"]];
SentryId *eventId = [[SentryId alloc]
initWithUUIDString:envelopeDict[@"header"][@"event_id"]];
if ([NSJSONSerialization isValidJSONObject:headerDict] &&
[NSJSONSerialization isValidJSONObject:payloadDict]) {
SentrySdkInfo *sdkInfo = [[SentrySdkInfo alloc] initWithDict:headerDict];
SentryId *eventId =
[[SentryId alloc] initWithUUIDString:headerDict[@"event_id"]];
SentryEnvelopeHeader *envelopeHeader =
[[SentryEnvelopeHeader alloc] initWithId:eventId andSdkInfo:sdkInfo];

NSError *error;
NSData *envelopeItemData =
[NSJSONSerialization dataWithJSONObject:envelopeDict[@"payload"]
[NSJSONSerialization dataWithJSONObject:payloadDict
options:0
error:&error];
if (nil != error) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
messageAsBool:NO];
} else {
NSString *itemType = envelopeDict[@"payload"][@"type"];
NSString *itemType = payloadDict[@"type"];
if (itemType == nil) {
// Default to event type.
itemType = @"event";
Expand All @@ -118,7 +120,7 @@ - (void)captureEnvelope:(CDVInvokedUrlCommand *)command {
#if DEBUG
[[SentrySDK currentHub] captureEnvelope:envelope];
#else
if ([envelopeDict[@"payload"][@"level"] isEqualToString:@"fatal"]) {
if ([payloadDict[@"level"] isEqualToString:@"fatal"]) {
// Storing to disk happens asynchronously with captureEnvelope
// We need to make sure the event is written to disk before resolving
// the promise. This could be replaced by SentrySDK.flush() when
Expand Down
25 changes: 3 additions & 22 deletions src/js/wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,36 +98,17 @@ export const NATIVE = {

if (getPlatform() === CordovaPlatformType.Android) {
const headerString = JSON.stringify(header);

const payloadString = JSON.stringify(payload);
let length = payloadString.length;
try {
length = await this._nativeCall('getStringBytesLength', payloadString);
} catch {
// The native call failed, we do nothing, we have payload.length as a fallback
}

const item = {
content_type: 'application/json',
length,
type: payload.type ?? 'event',
};
const payloadType = payload.type ?? 'event';

const itemString = JSON.stringify(item);

const envelopeString = `${headerString}\n${itemString}\n${payloadString}`;

return this._nativeCall('captureEnvelope', envelopeString);
return this._nativeCall('captureEnvelope', headerString, payloadString, payloadType);
}

// Serialize and remove any instances that will crash the native bridge such as Spans
const serializedPayload = JSON.parse(JSON.stringify(payload));

// The envelope item is created (and its length determined) on the iOS side of the native bridge.
return this._nativeCall('captureEnvelope', {
header,
payload: serializedPayload,
});
return this._nativeCall('captureEnvelope', header, serializedPayload);
},

/**
Expand Down

0 comments on commit 8bd1235

Please sign in to comment.