Skip to content

fix(android): resolve an OOM in network logs #1244

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

Merged
merged 15 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [Unreleased](https://github.com/Instabug/Instabug-React-Native/compare/v13.2.0...dev)

### Fixed

- Fix an OOM (out-of-memory) crash while saving network logs on Android ([#1244](https://github.com/Instabug/Instabug-React-Native/pull/1244)).

## [13.2.0](https://github.com/Instabug/Instabug-React-Native/compare/v13.1.1...v13.2.0) (July 7, 2024)

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
Expand Down Expand Up @@ -312,56 +314,58 @@ public void run() {
});
}

/**
* Send Apm network log by Reflection
*/
@ReactMethod
public void networkLog(String networkData) throws JSONException {
try{
APMNetworkLogger apmNetworkLogger = new APMNetworkLogger();
JSONObject jsonObject = new JSONObject(networkData);
final String requestUrl = (String) jsonObject.get("url");
final String requestBody = (String) jsonObject.get("requestBody");
final String responseBody = (String) jsonObject.get("responseBody");
final String requestMethod = (String) jsonObject.get("method");
//--------------------------------------------
final String requestContentType = (String) jsonObject.get("requestContentType");
final String responseContentType = (String) jsonObject.get("contentType");
//--------------------------------------------
final long requestBodySize = ((Number) jsonObject.get("requestBodySize")).longValue();
final long responseBodySize = ((Number) jsonObject.get("responseBodySize")).longValue();
//--------------------------------------------
final String errorDomain = (String) jsonObject.get("errorDomain");
final Integer statusCode = (Integer) jsonObject.get("responseCode");
final long requestDuration = ((Number) jsonObject.get("duration")).longValue();
final long requestStartTime = ((Number) jsonObject.get("startTime")).longValue() * 1000;
final String requestHeaders = (String) jsonObject.get("requestHeaders").toString();
final String responseHeaders = (String) jsonObject.get("responseHeaders").toString();
final String errorMessage;
if(errorDomain.equals("")) {
errorMessage = null;
} else {
errorMessage = errorDomain;
}
//--------------------------------------------
String gqlQueryName = null;
if(jsonObject.has("gqlQueryName")){
gqlQueryName = (String) jsonObject.get("gqlQueryName");
}
final String serverErrorMessage = (String) jsonObject.get("serverErrorMessage");
private void networkLogAndroid(final double requestStartTime,
final double requestDuration,
final String requestHeaders,
final String requestBody,
final double requestBodySize,
final String requestMethod,
final String requestUrl,
final String requestContentType,
final String responseHeaders,
final String responseBody,
final double responseBodySize,
final double statusCode,
final String responseContentType,
@Nullable final String errorDomain,
@Nullable final String gqlQueryName,
@Nullable final String serverErrorMessage) {
try {
APMNetworkLogger networkLogger = new APMNetworkLogger();

final boolean hasError = errorDomain != null && !errorDomain.isEmpty();
final String errorMessage = hasError ? errorDomain : null;

try {
Method method = getMethod(Class.forName("com.instabug.apm.networking.APMNetworkLogger"), "log", long.class, long.class, String.class, String.class, long.class, String.class, String.class, String.class, String.class, String.class, long.class, int.class, String.class, String.class, String.class, String.class);
if (method != null) {
method.invoke(apmNetworkLogger, requestStartTime, requestDuration, requestHeaders, requestBody, requestBodySize, requestMethod, requestUrl, requestContentType, responseHeaders, responseBody, responseBodySize, statusCode, responseContentType, errorMessage, gqlQueryName, serverErrorMessage);
method.invoke(
networkLogger,
requestStartTime,
requestDuration,
requestHeaders,
requestBody,
requestBodySize,
requestMethod,
requestUrl,
requestContentType,
responseHeaders,
responseBody,
responseBodySize,
statusCode,
responseContentType,
errorMessage,
gqlQueryName,
serverErrorMessage
);
} else {
Log.e("IB-CP-Bridge", "apmNetworkLogByReflection was not found by reflection");
Log.e("IB-CP-Bridge", "APMNetworkLogger.log was not found by reflection");
}
} catch (Throwable e) {
e.printStackTrace();
}
}
catch(Throwable e) {
} catch(Throwable e) {
e.printStackTrace();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.app.Application;
import android.graphics.Bitmap;
import android.net.Uri;
import android.util.Log;
import android.view.View;

import androidx.annotation.UiThread;
Expand Down Expand Up @@ -34,6 +35,7 @@
import com.instabug.library.model.NetworkLog;
import com.instabug.library.model.Report;
import com.instabug.library.ui.onboarding.WelcomeMessage;
import com.instabug.library.util.InstabugSDKLogger;
import com.instabug.reactlibrary.utils.ArrayUtil;
import com.instabug.reactlibrary.utils.EventEmitterModule;
import com.instabug.reactlibrary.utils.MainThreadHandler;
Expand All @@ -60,7 +62,7 @@
*/
public class RNInstabugReactnativeModule extends EventEmitterModule {

private static final String TAG = RNInstabugReactnativeModule.class.getSimpleName();
private static final String TAG = "IBG-RN-Core";

private InstabugCustomTextPlaceHolder placeHolders;
private static Report currentReport;
Expand Down Expand Up @@ -895,27 +897,38 @@ public void run() {
});
}

/**
* Extracts HTTP connection properties. Request method, Headers, Date, Url and Response code
*
* @param jsonObject the JSON object containing all HTTP connection properties
* @throws JSONException
*/
@ReactMethod
public void networkLog(String jsonObject) throws JSONException {
NetworkLog networkLog = new NetworkLog();
String date = System.currentTimeMillis()+"";
networkLog.setDate(date);
JSONObject newJSONObject = new JSONObject(jsonObject);
networkLog.setUrl(newJSONObject.getString("url"));
networkLog.setRequest(newJSONObject.getString("requestBody"));
networkLog.setResponse(newJSONObject.getString("responseBody"));
networkLog.setMethod(newJSONObject.getString("method"));
networkLog.setResponseCode(newJSONObject.getInt("responseCode"));
networkLog.setRequestHeaders(newJSONObject.getString("requestHeaders"));
networkLog.setResponseHeaders(newJSONObject.getString("responseHeaders"));
networkLog.setTotalDuration(newJSONObject.getLong("duration"));
networkLog.insert();
public void networkLogAndroid(final String url,
final String requestBody,
final String responseBody,
final String method,
final double responseCode,
final String requestHeaders,
final String responseHeaders,
final double duration) {
try {
final String date = String.valueOf(System.currentTimeMillis());

NetworkLog networkLog = new NetworkLog();
networkLog.setDate(date);
networkLog.setUrl(url);
networkLog.setMethod(method);
networkLog.setResponseCode((int) responseCode);
networkLog.setTotalDuration((long) duration);

try {
networkLog.setRequest(requestBody);
networkLog.setResponse(responseBody);
networkLog.setRequestHeaders(requestHeaders);
networkLog.setResponseHeaders(responseHeaders);
} catch (OutOfMemoryError | Exception exception) {
Log.d(TAG, "Error: " + exception.getMessage() + "while trying to set network log contents (request body, response body, request headers, and response headers).");
}

networkLog.insert();
} catch (OutOfMemoryError | Exception exception) {
Log.d(TAG, "Error: " + exception.getMessage() + "while trying to insert a network log");
}
}

@UiThread
Expand Down
56 changes: 56 additions & 0 deletions examples/default/ios/InstabugTests/InstabugSampleTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#import <Instabug/IBGTypes.h>
#import "IBGConstants.h"
#import "RNInstabug.h"
#import <RNInstabug/IBGNetworkLogger+CP.h>

@protocol InstabugCPTestProtocol <NSObject>
/**
Expand Down Expand Up @@ -313,6 +314,61 @@ - (void)testSetWelcomeMessageMode {
OCMVerify([mock setWelcomeMessageMode:welcomeMessageMode]);
}

- (void)testNetworkLogIOS {
id mIBGNetworkLogger = OCMClassMock([IBGNetworkLogger class]);

NSString *url = @"https://api.instabug.com";
NSString *method = @"GET";
NSString *requestBody = @"requestBody";
double requestBodySize = 10;
NSString *responseBody = @"responseBody";
double responseBodySize = 15;
double responseCode = 200;
NSDictionary *requestHeaders = @{ @"accept": @"application/json" };
NSDictionary *responseHeaders = @{ @"cache-control": @"no-store" };
NSString *contentType = @"application/json";
double errorCode = 0;
NSString *errorDomain = nil;
double startTime = 1719847101199;
double duration = 150;
NSString *gqlQueryName = nil;
NSString *serverErrorMessage = nil;

[self.instabugBridge networkLogIOS:url
method:method
requestBody:requestBody
requestBodySize:requestBodySize
responseBody:responseBody
responseBodySize:responseBodySize
responseCode:responseCode
requestHeaders:requestHeaders
responseHeaders:responseHeaders
contentType:contentType
errorDomain:errorDomain
errorCode:errorCode
startTime:startTime
duration:duration
gqlQueryName:gqlQueryName
serverErrorMessage:serverErrorMessage];

OCMVerify([mIBGNetworkLogger addNetworkLogWithUrl:url
method:method
requestBody:requestBody
requestBodySize:requestBodySize
responseBody:responseBody
responseBodySize:responseBodySize
responseCode:responseCode
requestHeaders:requestHeaders
responseHeaders:responseHeaders
contentType:contentType
errorDomain:errorDomain
errorCode:errorCode
startTime:startTime * 1000
duration:duration * 1000
gqlQueryName:gqlQueryName
serverErrorMessage:serverErrorMessage]);
}

- (void)testSetFileAttachment {
id mock = OCMClassMock([Instabug class]);
NSString *fileLocation = @"test";
Expand Down
17 changes: 17 additions & 0 deletions ios/RNInstabug/InstabugReactBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,23 @@

- (void)setNetworkLoggingEnabled:(BOOL)isEnabled;

- (void)networkLogIOS:(NSString * _Nonnull)url
method:(NSString * _Nonnull)method
requestBody:(NSString * _Nonnull)requestBody
requestBodySize:(double)requestBodySize
responseBody:(NSString * _Nonnull)responseBody
responseBodySize:(double)responseBodySize
responseCode:(double)responseCode
requestHeaders:(NSDictionary * _Nonnull)requestHeaders
responseHeaders:(NSDictionary * _Nonnull)responseHeaders
contentType:(NSString * _Nonnull)contentType
errorDomain:(NSString * _Nullable)errorDomain
errorCode:(double)errorCode
startTime:(double)startTime
duration:(double)duration
gqlQueryName:(NSString * _Nullable)gqlQueryName
serverErrorMessage:(NSString * _Nullable)serverErrorMessage;

/*
+------------------------------------------------------------------------+
| Experiments |
Expand Down
Loading