From 29e593de907b855a02a46b95ed627e9630bdfd4d Mon Sep 17 00:00:00 2001 From: mchavez-newrelic <132291725+mchavez-newrelic@users.noreply.github.com> Date: Fri, 14 Jul 2023 07:40:16 -0700 Subject: [PATCH 01/15] Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes --- README.md | 2 +- src/android/NewRelicCordovaPlugin.java | 8 ++++++++ src/ios/NewRelicCordovaPlugin.m | 6 ++++++ tests/tests.js | 18 ++++++++++++++++-- www/js/newrelic.js | 9 +++++++-- 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b842ea0..105c517 100644 --- a/README.md +++ b/README.md @@ -244,7 +244,7 @@ By default, these configurations are already set to true on agent start. ``` ## Error Reporting -### recordError(err: [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)) : void; +### recordError(err: [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error), attributes?: {[key: string]: boolean | number | string}) : void; Records JavaScript errors for Cordova. It is useful to add this method by adding it to the error handler of the framework that you are using. Here are some examples below: ### Angular diff --git a/src/android/NewRelicCordovaPlugin.java b/src/android/NewRelicCordovaPlugin.java index 7b061f0..e6ad5c4 100644 --- a/src/android/NewRelicCordovaPlugin.java +++ b/src/android/NewRelicCordovaPlugin.java @@ -208,12 +208,20 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo final String errorMessage = args.getString(1); final String errorStack = args.getString(2); final Boolean isFatal = args.getBoolean(3); + final JSONObject attributesAsJson = args.getJSONObject(4); HashMap exceptionMap = new HashMap<>(); try { exceptionMap.put("name", errorName); exceptionMap.put("message", errorMessage); exceptionMap.put("isFatal", isFatal); + if (attributesAsJson != null) { + final Map attributes = new Gson().fromJson(String.valueOf(attributesAsJson), + Map.class); + for (String key : attributes.keySet()) { + exceptionMap.put(key, attributes.get(key)); + } + } } catch (IllegalArgumentException e) { Log.w("NRMA", e.getMessage()); } diff --git a/src/ios/NewRelicCordovaPlugin.m b/src/ios/NewRelicCordovaPlugin.m index 98a8d72..7f49900 100644 --- a/src/ios/NewRelicCordovaPlugin.m +++ b/src/ios/NewRelicCordovaPlugin.m @@ -197,6 +197,7 @@ - (void)recordError:(CDVInvokedUrlCommand *)command { NSString* errorMessage = [command.arguments objectAtIndex:1]; NSString* errorStack = [command.arguments objectAtIndex:2]; NSString* isFatal = @"false"; + NSDictionary* errorAttributes = [command.arguments objectAtIndex:4]; if ([[command.arguments objectAtIndex:3] boolValue] == YES) { isFatal = @"true"; @@ -207,6 +208,11 @@ - (void)recordError:(CDVInvokedUrlCommand *)command { attributes[@"cause"] = errorMessage; attributes[@"reason"] = errorMessage; attributes[@"fatal"] = isFatal; + if (errorAttributes != nil && ![errorAttributes isKindOfClass:[NSNull class]]) { + for(id key in errorAttributes) { + attributes[key] = errorAttributes[key]; + } + } NSMutableArray* stackTraceArr = [self parseStackTrace:errorStack]; attributes[@"stackTraceElements"] = stackTraceArr; diff --git a/tests/tests.js b/tests/tests.js index 8d41e6d..0e6e906 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -134,6 +134,20 @@ exports.defineAutoTests = () => { window.NewRelic.recordError(new ReferenceError); window.NewRelic.recordError(new Error); + // should parse errors with non-empty custom attributes + let errorAttributes = new Map([ + ["errorKey1", "errorValue1"], + ["errorKey2", 2], + ["errorKey3", true] + ]); + window.NewRelic.recordError(exampleError, errorAttributes); + + // should parse errors with null custom attributes + window.NewRelic.recordError(exampleError, null); + + // should parse errors with empty custom attributes + window.NewRelic.recordError(exampleError, {}); + // Bad arguments window.NewRelic.recordError(undefined); window.NewRelic.recordError(null); @@ -141,8 +155,8 @@ exports.defineAutoTests = () => { window.NewRelic.recordError(true); let numOfNativeCalls = cordova.exec.calls.count() - window.console.warn.calls.count(); - expect(numOfNativeCalls).toBe(6); - expect(window.NewRelic.recordError).toHaveBeenCalledTimes(10); + expect(numOfNativeCalls).toBe(9); + expect(window.NewRelic.recordError).toHaveBeenCalledTimes(13); }); it('should parse JS error with missing fields', () => { diff --git a/www/js/newrelic.js b/www/js/newrelic.js index 3c9fe5c..064af17 100644 --- a/www/js/newrelic.js +++ b/www/js/newrelic.js @@ -125,8 +125,13 @@ var NewRelic = { /** * Records JavaScript errors for Cordova. * @param {Error} err The error to record. + * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. */ - recordError: function(err, cb, fail) { + recordError: function(err, attributes={}, cb, fail) { + let errorAttributes = attributes instanceof Map ? Object.fromEntries(attributes) : attributes; + if (attributes === null) { + errorAttributes = {}; + } if (err) { var error; @@ -139,7 +144,7 @@ var NewRelic = { } if(error !== undefined) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false]); + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false, errorAttributes]); } else { window.console.warn('Undefined error in NewRelic.recordError'); } From 6978ec9668ecf1297e2ed0e71d0d5d5bbc63c0e8 Mon Sep 17 00:00:00 2001 From: mchavez-newrelic <132291725+mchavez-newrelic@users.noreply.github.com> Date: Fri, 14 Jul 2023 07:40:16 -0700 Subject: [PATCH 02/15] Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes --- README.md | 2 +- src/android/NewRelicCordovaPlugin.java | 8 ++++++++ src/ios/NewRelicCordovaPlugin.m | 6 ++++++ tests/tests.js | 18 ++++++++++++++++-- www/js/newrelic.js | 9 +++++++-- 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b842ea0..105c517 100644 --- a/README.md +++ b/README.md @@ -244,7 +244,7 @@ By default, these configurations are already set to true on agent start. ``` ## Error Reporting -### recordError(err: [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)) : void; +### recordError(err: [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error), attributes?: {[key: string]: boolean | number | string}) : void; Records JavaScript errors for Cordova. It is useful to add this method by adding it to the error handler of the framework that you are using. Here are some examples below: ### Angular diff --git a/src/android/NewRelicCordovaPlugin.java b/src/android/NewRelicCordovaPlugin.java index 7b061f0..e6ad5c4 100644 --- a/src/android/NewRelicCordovaPlugin.java +++ b/src/android/NewRelicCordovaPlugin.java @@ -208,12 +208,20 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo final String errorMessage = args.getString(1); final String errorStack = args.getString(2); final Boolean isFatal = args.getBoolean(3); + final JSONObject attributesAsJson = args.getJSONObject(4); HashMap exceptionMap = new HashMap<>(); try { exceptionMap.put("name", errorName); exceptionMap.put("message", errorMessage); exceptionMap.put("isFatal", isFatal); + if (attributesAsJson != null) { + final Map attributes = new Gson().fromJson(String.valueOf(attributesAsJson), + Map.class); + for (String key : attributes.keySet()) { + exceptionMap.put(key, attributes.get(key)); + } + } } catch (IllegalArgumentException e) { Log.w("NRMA", e.getMessage()); } diff --git a/src/ios/NewRelicCordovaPlugin.m b/src/ios/NewRelicCordovaPlugin.m index f0623d3..4c36e85 100644 --- a/src/ios/NewRelicCordovaPlugin.m +++ b/src/ios/NewRelicCordovaPlugin.m @@ -197,6 +197,7 @@ - (void)recordError:(CDVInvokedUrlCommand *)command { NSString* errorMessage = [command.arguments objectAtIndex:1]; NSString* errorStack = [command.arguments objectAtIndex:2]; NSString* isFatal = @"false"; + NSDictionary* errorAttributes = [command.arguments objectAtIndex:4]; if ([[command.arguments objectAtIndex:3] boolValue] == YES) { isFatal = @"true"; @@ -207,6 +208,11 @@ - (void)recordError:(CDVInvokedUrlCommand *)command { attributes[@"cause"] = errorMessage; attributes[@"reason"] = errorMessage; attributes[@"fatal"] = isFatal; + if (errorAttributes != nil && ![errorAttributes isKindOfClass:[NSNull class]]) { + for(id key in errorAttributes) { + attributes[key] = errorAttributes[key]; + } + } NSMutableArray* stackTraceArr = [self parseStackTrace:errorStack]; attributes[@"stackTraceElements"] = stackTraceArr; diff --git a/tests/tests.js b/tests/tests.js index 8d41e6d..0e6e906 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -134,6 +134,20 @@ exports.defineAutoTests = () => { window.NewRelic.recordError(new ReferenceError); window.NewRelic.recordError(new Error); + // should parse errors with non-empty custom attributes + let errorAttributes = new Map([ + ["errorKey1", "errorValue1"], + ["errorKey2", 2], + ["errorKey3", true] + ]); + window.NewRelic.recordError(exampleError, errorAttributes); + + // should parse errors with null custom attributes + window.NewRelic.recordError(exampleError, null); + + // should parse errors with empty custom attributes + window.NewRelic.recordError(exampleError, {}); + // Bad arguments window.NewRelic.recordError(undefined); window.NewRelic.recordError(null); @@ -141,8 +155,8 @@ exports.defineAutoTests = () => { window.NewRelic.recordError(true); let numOfNativeCalls = cordova.exec.calls.count() - window.console.warn.calls.count(); - expect(numOfNativeCalls).toBe(6); - expect(window.NewRelic.recordError).toHaveBeenCalledTimes(10); + expect(numOfNativeCalls).toBe(9); + expect(window.NewRelic.recordError).toHaveBeenCalledTimes(13); }); it('should parse JS error with missing fields', () => { diff --git a/www/js/newrelic.js b/www/js/newrelic.js index 3c9fe5c..064af17 100644 --- a/www/js/newrelic.js +++ b/www/js/newrelic.js @@ -125,8 +125,13 @@ var NewRelic = { /** * Records JavaScript errors for Cordova. * @param {Error} err The error to record. + * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. */ - recordError: function(err, cb, fail) { + recordError: function(err, attributes={}, cb, fail) { + let errorAttributes = attributes instanceof Map ? Object.fromEntries(attributes) : attributes; + if (attributes === null) { + errorAttributes = {}; + } if (err) { var error; @@ -139,7 +144,7 @@ var NewRelic = { } if(error !== undefined) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false]); + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false, errorAttributes]); } else { window.console.warn('Undefined error in NewRelic.recordError'); } From efe8bccc2affcb13fc809cb8049ff8d6017e735d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 26 Jul 2023 10:37:57 -0500 Subject: [PATCH 03/15] Update iOS agent to 7.4.6 (#73) * Update iOS Version to 7.4.6 * Release 6.2.3 --------- Co-authored-by: ndesai-newrelic Co-authored-by: ndesai-newrelic <89222514+ndesai-newrelic@users.noreply.github.com> --- CHANGELOG.md | 6 ++++++ plugin.xml | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93bc4b4..5885006 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +# 6.2.3 + +### New in this release +* Upgraded native iOS agent to v7.4.6 + + # 6.2.2 ### New in this release diff --git a/plugin.xml b/plugin.xml index e14602c..02290db 100644 --- a/plugin.xml +++ b/plugin.xml @@ -6,7 +6,7 @@ + id="newrelic-cordova-plugin" version="6.2.3"> NewRelic New Relic Cordova Plugin for iOS and Android New Relic @@ -18,7 +18,7 @@ - + @@ -68,7 +68,7 @@ - + From 783eb697e72deea06458ee95c38c5bb74262c988 Mon Sep 17 00:00:00 2001 From: mchavez-newrelic <132291725+mchavez-newrelic@users.noreply.github.com> Date: Fri, 14 Jul 2023 07:40:16 -0700 Subject: [PATCH 04/15] Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes --- src/android/NewRelicCordovaPlugin.java | 2 +- www/js/newrelic.js | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/android/NewRelicCordovaPlugin.java b/src/android/NewRelicCordovaPlugin.java index e7ae6ec..bc66ee0 100644 --- a/src/android/NewRelicCordovaPlugin.java +++ b/src/android/NewRelicCordovaPlugin.java @@ -232,7 +232,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo exceptionMap.put("isFatal", isFatal); if (attributesAsJson != null) { final Map attributes = new Gson().fromJson(String.valueOf(attributesAsJson), - Map.class); + Map.class); for (String key : attributes.keySet()) { exceptionMap.put(key, attributes.get(key)); } diff --git a/www/js/newrelic.js b/www/js/newrelic.js index 28bc1dd..0720426 100644 --- a/www/js/newrelic.js +++ b/www/js/newrelic.js @@ -145,13 +145,18 @@ cordova.define("newrelic-cordova-plugin.NewRelic", function(require, exports, mo * Records JavaScript errors for Cordova. * @param {Error} err The error to record. * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. - */ - recordError: function(err, attributes={}, cb, fail) { + * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. + */ + recordError: function(err, attributes={}, attributes={}, cb, fail) { let errorAttributes = attributes instanceof Map ? Object.fromEntries(attributes) : attributes; if (attributes === null) { errorAttributes = {}; } - if (err) { + let errorAttributes = attributes instanceof Map ? Object.fromEntries(attributes) : attributes; + if (attributes === null) { + errorAttributes = {}; + } + if (err) { var error; if (err instanceof Error) { @@ -163,7 +168,7 @@ cordova.define("newrelic-cordova-plugin.NewRelic", function(require, exports, mo } if(error !== undefined) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false, errorAttributes]); + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false, errorAttributes, errorAttributes]); } else { window.console.warn('Undefined error in NewRelic.recordError'); } From 4f3e1e89d817ec2a4dda56a5381fbaeb427d12cf Mon Sep 17 00:00:00 2001 From: mchavez-newrelic <132291725+mchavez-newrelic@users.noreply.github.com> Date: Fri, 14 Jul 2023 07:40:16 -0700 Subject: [PATCH 05/15] Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes --- www/js/newrelic.js | 389 +++++++++++++++++++++------------------------ 1 file changed, 181 insertions(+), 208 deletions(-) diff --git a/www/js/newrelic.js b/www/js/newrelic.js index 0720426..47c200e 100644 --- a/www/js/newrelic.js +++ b/www/js/newrelic.js @@ -147,223 +147,196 @@ cordova.define("newrelic-cordova-plugin.NewRelic", function(require, exports, mo * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. */ - recordError: function(err, attributes={}, attributes={}, cb, fail) { - let errorAttributes = attributes instanceof Map ? Object.fromEntries(attributes) : attributes; - if (attributes === null) { - errorAttributes = {}; - } - let errorAttributes = attributes instanceof Map ? Object.fromEntries(attributes) : attributes; - if (attributes === null) { - errorAttributes = {}; - } + recordError: function(err, cb, fail) { if (err) { - var error; - - if (err instanceof Error) { - error = err; - } - - if (typeof err === 'string') { - error = new Error(err || ''); - } - - if(error !== undefined) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false, errorAttributes, errorAttributes]); - } else { - window.console.warn('Undefined error in NewRelic.recordError'); - } - + var error; + + if (err instanceof Error) { + error = err; + } + + if (typeof err === 'string') { + error = new Error(err || ''); + } + + if(error !== undefined) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false]); } else { - window.console.warn('Error is required in NewRelic.recordError'); + window.console.warn('Undefined error in NewRelic.recordError'); } - }, - - /** - * Throws a demo run-time exception to test New Relic crash reporting. - * @param {string} message An optional argument attached to the exception. - */ - crashNow: function (message = '', cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "crashNow", [message]); - }, - - /** - * Returns the current session ID as a parameter to the successful callback function. - * This method is useful for consolidating monitoring of app data (not just New Relic data) based on a single session definition and identifier. - * @param {function} cb A success callback function. - * @returns {Promise} A promise containing the current session ID. - */ - currentSessionId: function (cb, fail) { - return new Promise(function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "currentSessionId"); - }); - }, - - /** - * Increments the count of an attribute with a specified name. - * When called, it overwrites its previous value and type each time. - * If attribute does not exist, it creates an attribute with a value of 1. - * The incremented attribute is shared by multiple Mobile event types. - * @param {string} name The name of the attribute. - * @param {number} value Optional argument that increments the attribute by this value. - */ - incrementAttribute: function(name, value=1, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "incrementAttribute", [name, value]); - }, - - /** - * Records network failures. - * If a network request fails, use this method to record details about the failure. - * In most cases, place this call inside exception handlers. - * @param {string} url The URL of the request. - * @param {string} httpMethod The HTTP method used, such as GET or POST. - * @param {number} startTime The start time of the request in milliseconds since the epoch. - * @param {number} endTime The end time of the request in milliseconds since the epoch. - * @param {string} failure The name of the network failure. Possible values are 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'. - */ - noticeNetworkFailure: function (url, httpMethod, startTime, endTime, failure, cb, fail) { - const failureNames = new Set(['Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed']); - if (!failureNames.has(failure)) { - window.console.error("NewRelic.noticeNetworkFailure: Network failure name has to be one of: 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'"); + + } else { + window.console.warn('Error is required in NewRelic.recordError'); + } + }, + + /** + * Throws a demo run-time exception to test New Relic crash reporting. + * @param {string} message An optional argument attached to the exception. + */ + crashNow: function (message = '', cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "crashNow", [message]); + }, + + /** + * Returns the current session ID as a parameter to the successful callback function. + * This method is useful for consolidating monitoring of app data (not just New Relic data) based on a single session definition and identifier. + * @param {function} cb A success callback function. + * @returns {Promise} A promise containing the current session ID. + */ + currentSessionId: function (cb, fail) { + return new Promise(function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "currentSessionId"); + }); + }, + + /** + * Increments the count of an attribute with a specified name. + * When called, it overwrites its previous value and type each time. + * If attribute does not exist, it creates an attribute with a value of 1. + * The incremented attribute is shared by multiple Mobile event types. + * @param {string} name The name of the attribute. + * @param {number} value Optional argument that increments the attribute by this value. + */ + incrementAttribute: function(name, value=1, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "incrementAttribute", [name, value]); + }, + + /** + * Records network failures. + * If a network request fails, use this method to record details about the failure. + * In most cases, place this call inside exception handlers. + * @param {string} url The URL of the request. + * @param {string} httpMethod The HTTP method used, such as GET or POST. + * @param {number} startTime The start time of the request in milliseconds since the epoch. + * @param {number} endTime The end time of the request in milliseconds since the epoch. + * @param {string} failure The name of the network failure. Possible values are 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'. + */ + noticeNetworkFailure: function (url, httpMethod, startTime, endTime, failure, cb, fail) { + const failureNames = new Set(['Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed']); + if (!failureNames.has(failure)) { + window.console.error("NewRelic.noticeNetworkFailure: Network failure name has to be one of: 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'"); + return; + } + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeNetworkFailure", [url, httpMethod, startTime, endTime, failure]); + }, + + /** + * + * @param {string} name The name for the custom metric. + * @param {string} category The metric category name. + * @param {number} value Optional. The value of the metric. Value should be a non-zero positive number. + * @param {string} countUnit Optional (but requires value and valueUnit to be set). Unit of measurement for the metric count. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. + * @param {string} valueUnit Optional (but requires value and countUnit to be set). Unit of measurement for the metric value. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. + */ + recordMetric: function (name, category, value = -1, countUnit = null, valueUnit = null, cb, fail) { + const metricUnits = new Set(['PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS']); + if (value < 0) { + if (countUnit !== null || valueUnit !== null) { + window.console.error('NewRelic.recordMetric: value must be set in recordMetric if countUnit and valueUnit are set'); return; } - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeNetworkFailure", [url, httpMethod, startTime, endTime, failure]); - }, - - /** - * - * @param {string} name The name for the custom metric. - * @param {string} category The metric category name. - * @param {number} value Optional. The value of the metric. Value should be a non-zero positive number. - * @param {string} countUnit Optional (but requires value and valueUnit to be set). Unit of measurement for the metric count. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. - * @param {string} valueUnit Optional (but requires value and countUnit to be set). Unit of measurement for the metric value. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. - */ - recordMetric: function (name, category, value = -1, countUnit = null, valueUnit = null, cb, fail) { - const metricUnits = new Set(['PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS']); - if (value < 0) { - if (countUnit !== null || valueUnit !== null) { - window.console.error('NewRelic.recordMetric: value must be set in recordMetric if countUnit and valueUnit are set'); - return; - } - } else { - if ((countUnit !== null && valueUnit == null) || (countUnit == null && valueUnit !== null)) { - window.console.error('NewRelic.recordMetric: countUnit and valueUnit in recordMetric must both be null or set'); + } else { + if ((countUnit !== null && valueUnit == null) || (countUnit == null && valueUnit !== null)) { + window.console.error('NewRelic.recordMetric: countUnit and valueUnit in recordMetric must both be null or set'); + return; + } else if (countUnit !== null && valueUnit !== null) { + if (!metricUnits.has(countUnit) || !metricUnits.has(valueUnit)) { + window.console.error("NewRelic.recordMetric: countUnit or valueUnit in recordMetric has to be one of 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS'"); return; - } else if (countUnit !== null && valueUnit !== null) { - if (!metricUnits.has(countUnit) || !metricUnits.has(valueUnit)) { - window.console.error("NewRelic.recordMetric: countUnit or valueUnit in recordMetric has to be one of 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS'"); - return; - } } } - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordMetric", [name, category, value, countUnit, valueUnit]); - }, - - /** - * Removes all attributes from the session.. - */ - removeAllAttributes: function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "removeAllAttributes"); - }, - - /** - * Sets the event harvest cycle length. - * Default is 600 seconds (10 minutes). - * Minimum value cannot be less than 60 seconds. - * Maximum value should not be greater than 600 seconds. - * @param {number} maxBufferTimeInSeconds The maximum time (in seconds) that the agent should store events in memory. - */ - setMaxEventBufferTime: function (maxBufferTimeInSeconds, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventBufferTime", [maxBufferTimeInSeconds]); - }, - - /** - * Sets the maximum size of the event pool stored in memory until the next harvest cycle. - * When the pool size limit is reached, the agent will start sampling events, discarding some new and old, until the pool of events is sent in the next harvest cycle. - * Default is a maximum of 1000 events per event harvest cycle. - * @param {number} maxPoolSize The maximum number of events per harvest cycle. - */ - setMaxEventPoolSize: function (maxPoolSize, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventPoolSize", [maxPoolSize]); - }, - - /** - * FOR ANDROID ONLY. - * Enable or disable collection of event data. - * @param {boolean} enabled Boolean value for enabling analytics events. - */ - analyticsEventEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "analyticsEventEnabled", [enabled]); - }, - - /** - * Enable or disable reporting sucessful HTTP request to the MobileRequest event type. - * @param {boolean} enabled Boolean value for enable successful HTTP requests. - */ - networkRequestEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkRequestEnabled", [enabled]); - }, - - /** - * Enable or disable reporting network and HTTP request errors to the MobileRequestError event type. - * @param {boolean} enabled Boolean value for enabling network request errors. - */ - networkErrorRequestEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkErrorRequestEnabled", [enabled]); - }, - - /** - * Enable or disable capture of HTTP response bodies for HTTP error traces, and MobileRequestError events. - * @param {boolean} enabled Boolean value for enabling HTTP response bodies. - */ - httpRequestBodyCaptureEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "httpRequestBodyCaptureEnabled", [enabled]); - }, - - /** - * Shut down the agent within the current application lifecycle during runtime. - * Once the agent has shut down, it cannot be restarted within the current application lifecycle. - */ - shutdown: function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "shutdown"); - }, - - addHTTPHeadersTrackingFor: function (headers,cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "addHTTPHeadersTrackingFor",[headers]); - }, - - getHTTPHeadersTrackingFor: function (cb, fail) { - - return new Promise(function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "getHTTPHeadersTrackingFor"); - }); - }, - - generateDistributedTracingHeaders: function (cb, fail) { - - return new Promise(function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "generateDistributedTracingHeaders"); - }); - }, - - } - - networkRequest = {}; - var originalXhrOpen = XMLHttpRequest.prototype.open; - var originalXHRSend = XMLHttpRequest.prototype.send; + } + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordMetric", [name, category, value, countUnit, valueUnit]); + }, - window.XMLHttpRequest.prototype.open = function (method, url) { - // Keep track of the method and url - // start time is tracked by the `send` method - - // eslint-disable-next-line prefer-rest-params - - networkRequest.url = url; - networkRequest.method = method; - networkRequest.bytesSent = 0; - networkRequest.startTime = Date.now(); - return originalXhrOpen.apply(this, arguments) - - } + /** + * Removes all attributes from the session.. + */ + removeAllAttributes: function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "removeAllAttributes"); + }, + + /** + * Sets the event harvest cycle length. + * Default is 600 seconds (10 minutes). + * Minimum value cannot be less than 60 seconds. + * Maximum value should not be greater than 600 seconds. + * @param {number} maxBufferTimeInSeconds The maximum time (in seconds) that the agent should store events in memory. + */ + setMaxEventBufferTime: function (maxBufferTimeInSeconds, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventBufferTime", [maxBufferTimeInSeconds]); + }, + + /** + * Sets the maximum size of the event pool stored in memory until the next harvest cycle. + * When the pool size limit is reached, the agent will start sampling events, discarding some new and old, until the pool of events is sent in the next harvest cycle. + * Default is a maximum of 1000 events per event harvest cycle. + * @param {number} maxPoolSize The maximum number of events per harvest cycle. + */ + setMaxEventPoolSize: function (maxPoolSize, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventPoolSize", [maxPoolSize]); + }, + + /** + * FOR ANDROID ONLY. + * Enable or disable collection of event data. + * @param {boolean} enabled Boolean value for enabling analytics events. + */ + analyticsEventEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "analyticsEventEnabled", [enabled]); + }, + + /** + * Enable or disable reporting sucessful HTTP request to the MobileRequest event type. + * @param {boolean} enabled Boolean value for enable successful HTTP requests. + */ + networkRequestEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkRequestEnabled", [enabled]); + }, + + /** + * Enable or disable reporting network and HTTP request errors to the MobileRequestError event type. + * @param {boolean} enabled Boolean value for enabling network request errors. + */ + networkErrorRequestEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkErrorRequestEnabled", [enabled]); + }, + + /** + * Enable or disable capture of HTTP response bodies for HTTP error traces, and MobileRequestError events. + * @param {boolean} enabled Boolean value for enabling HTTP response bodies. + */ + httpRequestBodyCaptureEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "httpRequestBodyCaptureEnabled", [enabled]); + }, + + /** + * Shut down the agent within the current application lifecycle during runtime. + * Once the agent has shut down, it cannot be restarted within the current application lifecycle. + */ + shutdown: function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "shutdown"); + }, + +} + +networkRequest = {}; +var originalXhrOpen = XMLHttpRequest.prototype.open; +var originalXHRSend = XMLHttpRequest.prototype.send; +window.XMLHttpRequest.prototype.open = function (method, url) { + // Keep track of the method and url + // start time is tracked by the `send` method + + // eslint-disable-next-line prefer-rest-params + + networkRequest.url = url; + networkRequest.method = method; + networkRequest.bytesSent = 0; + networkRequest.startTime = Date.now(); + return originalXhrOpen.apply(this, arguments) + +} window.XMLHttpRequest.prototype.send = function (data) { From 120a648475a3f8249796bf9d554dbc07bc5852df Mon Sep 17 00:00:00 2001 From: ndesai-newrelic Date: Tue, 13 Feb 2024 13:45:17 -0600 Subject: [PATCH 06/15] resolve merge conflicts with master --- src/android/NewRelicCordovaPlugin.java | 2 +- www/js/newrelic.js | 352 +++++++++++++------------ 2 files changed, 188 insertions(+), 166 deletions(-) diff --git a/src/android/NewRelicCordovaPlugin.java b/src/android/NewRelicCordovaPlugin.java index bc66ee0..e7ae6ec 100644 --- a/src/android/NewRelicCordovaPlugin.java +++ b/src/android/NewRelicCordovaPlugin.java @@ -232,7 +232,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo exceptionMap.put("isFatal", isFatal); if (attributesAsJson != null) { final Map attributes = new Gson().fromJson(String.valueOf(attributesAsJson), - Map.class); + Map.class); for (String key : attributes.keySet()) { exceptionMap.put(key, attributes.get(key)); } diff --git a/www/js/newrelic.js b/www/js/newrelic.js index 47c200e..3b6359c 100644 --- a/www/js/newrelic.js +++ b/www/js/newrelic.js @@ -145,198 +145,220 @@ cordova.define("newrelic-cordova-plugin.NewRelic", function(require, exports, mo * Records JavaScript errors for Cordova. * @param {Error} err The error to record. * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. - * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. - */ - recordError: function(err, cb, fail) { - if (err) { - var error; - - if (err instanceof Error) { - error = err; + */ + recordError: function(err, attributes={}, cb, fail) { + let errorAttributes = attributes instanceof Map ? Object.fromEntries(attributes) : attributes; + if (attributes === null) { + errorAttributes = {}; } + if (err) { + var error; - if (typeof err === 'string') { - error = new Error(err || ''); - } + if (err instanceof Error) { + error = err; + } - if(error !== undefined) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false]); - } else { - window.console.warn('Undefined error in NewRelic.recordError'); - } + if (typeof err === 'string') { + error = new Error(err || ''); + } - } else { - window.console.warn('Error is required in NewRelic.recordError'); - } - }, + if(error !== undefined) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false, errorAttributes]); + } else { + window.console.warn('Undefined error in NewRelic.recordError'); + } - /** - * Throws a demo run-time exception to test New Relic crash reporting. - * @param {string} message An optional argument attached to the exception. - */ - crashNow: function (message = '', cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "crashNow", [message]); - }, + } else { + window.console.warn('Error is required in NewRelic.recordError'); + } + }, - /** - * Returns the current session ID as a parameter to the successful callback function. - * This method is useful for consolidating monitoring of app data (not just New Relic data) based on a single session definition and identifier. - * @param {function} cb A success callback function. - * @returns {Promise} A promise containing the current session ID. - */ - currentSessionId: function (cb, fail) { - return new Promise(function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "currentSessionId"); - }); - }, + /** + * Throws a demo run-time exception to test New Relic crash reporting. + * @param {string} message An optional argument attached to the exception. + */ + crashNow: function (message = '', cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "crashNow", [message]); + }, - /** - * Increments the count of an attribute with a specified name. - * When called, it overwrites its previous value and type each time. - * If attribute does not exist, it creates an attribute with a value of 1. - * The incremented attribute is shared by multiple Mobile event types. - * @param {string} name The name of the attribute. - * @param {number} value Optional argument that increments the attribute by this value. - */ - incrementAttribute: function(name, value=1, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "incrementAttribute", [name, value]); - }, + /** + * Returns the current session ID as a parameter to the successful callback function. + * This method is useful for consolidating monitoring of app data (not just New Relic data) based on a single session definition and identifier. + * @param {function} cb A success callback function. + * @returns {Promise} A promise containing the current session ID. + */ + currentSessionId: function (cb, fail) { + return new Promise(function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "currentSessionId"); + }); + }, - /** - * Records network failures. - * If a network request fails, use this method to record details about the failure. - * In most cases, place this call inside exception handlers. - * @param {string} url The URL of the request. - * @param {string} httpMethod The HTTP method used, such as GET or POST. - * @param {number} startTime The start time of the request in milliseconds since the epoch. - * @param {number} endTime The end time of the request in milliseconds since the epoch. - * @param {string} failure The name of the network failure. Possible values are 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'. - */ - noticeNetworkFailure: function (url, httpMethod, startTime, endTime, failure, cb, fail) { - const failureNames = new Set(['Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed']); - if (!failureNames.has(failure)) { - window.console.error("NewRelic.noticeNetworkFailure: Network failure name has to be one of: 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'"); - return; - } - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeNetworkFailure", [url, httpMethod, startTime, endTime, failure]); - }, + /** + * Increments the count of an attribute with a specified name. + * When called, it overwrites its previous value and type each time. + * If attribute does not exist, it creates an attribute with a value of 1. + * The incremented attribute is shared by multiple Mobile event types. + * @param {string} name The name of the attribute. + * @param {number} value Optional argument that increments the attribute by this value. + */ + incrementAttribute: function(name, value=1, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "incrementAttribute", [name, value]); + }, - /** - * - * @param {string} name The name for the custom metric. - * @param {string} category The metric category name. - * @param {number} value Optional. The value of the metric. Value should be a non-zero positive number. - * @param {string} countUnit Optional (but requires value and valueUnit to be set). Unit of measurement for the metric count. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. - * @param {string} valueUnit Optional (but requires value and countUnit to be set). Unit of measurement for the metric value. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. - */ - recordMetric: function (name, category, value = -1, countUnit = null, valueUnit = null, cb, fail) { - const metricUnits = new Set(['PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS']); - if (value < 0) { - if (countUnit !== null || valueUnit !== null) { - window.console.error('NewRelic.recordMetric: value must be set in recordMetric if countUnit and valueUnit are set'); + /** + * Records network failures. + * If a network request fails, use this method to record details about the failure. + * In most cases, place this call inside exception handlers. + * @param {string} url The URL of the request. + * @param {string} httpMethod The HTTP method used, such as GET or POST. + * @param {number} startTime The start time of the request in milliseconds since the epoch. + * @param {number} endTime The end time of the request in milliseconds since the epoch. + * @param {string} failure The name of the network failure. Possible values are 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'. + */ + noticeNetworkFailure: function (url, httpMethod, startTime, endTime, failure, cb, fail) { + const failureNames = new Set(['Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed']); + if (!failureNames.has(failure)) { + window.console.error("NewRelic.noticeNetworkFailure: Network failure name has to be one of: 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'"); return; } - } else { - if ((countUnit !== null && valueUnit == null) || (countUnit == null && valueUnit !== null)) { - window.console.error('NewRelic.recordMetric: countUnit and valueUnit in recordMetric must both be null or set'); - return; - } else if (countUnit !== null && valueUnit !== null) { - if (!metricUnits.has(countUnit) || !metricUnits.has(valueUnit)) { - window.console.error("NewRelic.recordMetric: countUnit or valueUnit in recordMetric has to be one of 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS'"); + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeNetworkFailure", [url, httpMethod, startTime, endTime, failure]); + }, + + /** + * + * @param {string} name The name for the custom metric. + * @param {string} category The metric category name. + * @param {number} value Optional. The value of the metric. Value should be a non-zero positive number. + * @param {string} countUnit Optional (but requires value and valueUnit to be set). Unit of measurement for the metric count. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. + * @param {string} valueUnit Optional (but requires value and countUnit to be set). Unit of measurement for the metric value. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. + */ + recordMetric: function (name, category, value = -1, countUnit = null, valueUnit = null, cb, fail) { + const metricUnits = new Set(['PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS']); + if (value < 0) { + if (countUnit !== null || valueUnit !== null) { + window.console.error('NewRelic.recordMetric: value must be set in recordMetric if countUnit and valueUnit are set'); return; } + } else { + if ((countUnit !== null && valueUnit == null) || (countUnit == null && valueUnit !== null)) { + window.console.error('NewRelic.recordMetric: countUnit and valueUnit in recordMetric must both be null or set'); + return; + } else if (countUnit !== null && valueUnit !== null) { + if (!metricUnits.has(countUnit) || !metricUnits.has(valueUnit)) { + window.console.error("NewRelic.recordMetric: countUnit or valueUnit in recordMetric has to be one of 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS'"); + return; + } + } } - } - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordMetric", [name, category, value, countUnit, valueUnit]); - }, + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordMetric", [name, category, value, countUnit, valueUnit]); + }, - /** - * Removes all attributes from the session.. - */ - removeAllAttributes: function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "removeAllAttributes"); - }, + /** + * Removes all attributes from the session.. + */ + removeAllAttributes: function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "removeAllAttributes"); + }, - /** - * Sets the event harvest cycle length. - * Default is 600 seconds (10 minutes). - * Minimum value cannot be less than 60 seconds. - * Maximum value should not be greater than 600 seconds. - * @param {number} maxBufferTimeInSeconds The maximum time (in seconds) that the agent should store events in memory. - */ - setMaxEventBufferTime: function (maxBufferTimeInSeconds, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventBufferTime", [maxBufferTimeInSeconds]); - }, + /** + * Sets the event harvest cycle length. + * Default is 600 seconds (10 minutes). + * Minimum value cannot be less than 60 seconds. + * Maximum value should not be greater than 600 seconds. + * @param {number} maxBufferTimeInSeconds The maximum time (in seconds) that the agent should store events in memory. + */ + setMaxEventBufferTime: function (maxBufferTimeInSeconds, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventBufferTime", [maxBufferTimeInSeconds]); + }, - /** - * Sets the maximum size of the event pool stored in memory until the next harvest cycle. - * When the pool size limit is reached, the agent will start sampling events, discarding some new and old, until the pool of events is sent in the next harvest cycle. - * Default is a maximum of 1000 events per event harvest cycle. - * @param {number} maxPoolSize The maximum number of events per harvest cycle. - */ - setMaxEventPoolSize: function (maxPoolSize, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventPoolSize", [maxPoolSize]); - }, + /** + * Sets the maximum size of the event pool stored in memory until the next harvest cycle. + * When the pool size limit is reached, the agent will start sampling events, discarding some new and old, until the pool of events is sent in the next harvest cycle. + * Default is a maximum of 1000 events per event harvest cycle. + * @param {number} maxPoolSize The maximum number of events per harvest cycle. + */ + setMaxEventPoolSize: function (maxPoolSize, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventPoolSize", [maxPoolSize]); + }, - /** - * FOR ANDROID ONLY. - * Enable or disable collection of event data. - * @param {boolean} enabled Boolean value for enabling analytics events. - */ - analyticsEventEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "analyticsEventEnabled", [enabled]); - }, + /** + * FOR ANDROID ONLY. + * Enable or disable collection of event data. + * @param {boolean} enabled Boolean value for enabling analytics events. + */ + analyticsEventEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "analyticsEventEnabled", [enabled]); + }, - /** - * Enable or disable reporting sucessful HTTP request to the MobileRequest event type. - * @param {boolean} enabled Boolean value for enable successful HTTP requests. - */ - networkRequestEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkRequestEnabled", [enabled]); - }, + /** + * Enable or disable reporting sucessful HTTP request to the MobileRequest event type. + * @param {boolean} enabled Boolean value for enable successful HTTP requests. + */ + networkRequestEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkRequestEnabled", [enabled]); + }, - /** - * Enable or disable reporting network and HTTP request errors to the MobileRequestError event type. - * @param {boolean} enabled Boolean value for enabling network request errors. - */ - networkErrorRequestEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkErrorRequestEnabled", [enabled]); - }, + /** + * Enable or disable reporting network and HTTP request errors to the MobileRequestError event type. + * @param {boolean} enabled Boolean value for enabling network request errors. + */ + networkErrorRequestEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkErrorRequestEnabled", [enabled]); + }, - /** - * Enable or disable capture of HTTP response bodies for HTTP error traces, and MobileRequestError events. - * @param {boolean} enabled Boolean value for enabling HTTP response bodies. - */ - httpRequestBodyCaptureEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "httpRequestBodyCaptureEnabled", [enabled]); - }, + /** + * Enable or disable capture of HTTP response bodies for HTTP error traces, and MobileRequestError events. + * @param {boolean} enabled Boolean value for enabling HTTP response bodies. + */ + httpRequestBodyCaptureEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "httpRequestBodyCaptureEnabled", [enabled]); + }, - /** - * Shut down the agent within the current application lifecycle during runtime. - * Once the agent has shut down, it cannot be restarted within the current application lifecycle. - */ - shutdown: function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "shutdown"); - }, + /** + * Shut down the agent within the current application lifecycle during runtime. + * Once the agent has shut down, it cannot be restarted within the current application lifecycle. + */ + shutdown: function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "shutdown"); + }, + + addHTTPHeadersTrackingFor: function (headers,cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "addHTTPHeadersTrackingFor",[headers]); + }, -} + getHTTPHeadersTrackingFor: function (cb, fail) { -networkRequest = {}; -var originalXhrOpen = XMLHttpRequest.prototype.open; -var originalXHRSend = XMLHttpRequest.prototype.send; -window.XMLHttpRequest.prototype.open = function (method, url) { - // Keep track of the method and url - // start time is tracked by the `send` method + return new Promise(function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "getHTTPHeadersTrackingFor"); + }); + }, + + generateDistributedTracingHeaders: function (cb, fail) { + + return new Promise(function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "generateDistributedTracingHeaders"); + }); + }, + + } + + networkRequest = {}; + var originalXhrOpen = XMLHttpRequest.prototype.open; + var originalXHRSend = XMLHttpRequest.prototype.send; - // eslint-disable-next-line prefer-rest-params + window.XMLHttpRequest.prototype.open = function (method, url) { + // Keep track of the method and url + // start time is tracked by the `send` method - networkRequest.url = url; - networkRequest.method = method; - networkRequest.bytesSent = 0; - networkRequest.startTime = Date.now(); - return originalXhrOpen.apply(this, arguments) + // eslint-disable-next-line prefer-rest-params -} + networkRequest.url = url; + networkRequest.method = method; + networkRequest.bytesSent = 0; + networkRequest.startTime = Date.now(); + return originalXhrOpen.apply(this, arguments) + + } window.XMLHttpRequest.prototype.send = function (data) { From cf845f2cb6f28ca1fb77217b2682edeb7b0c2233 Mon Sep 17 00:00:00 2001 From: mchavez-newrelic <132291725+mchavez-newrelic@users.noreply.github.com> Date: Fri, 14 Jul 2023 07:40:16 -0700 Subject: [PATCH 07/15] Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes --- src/android/NewRelicCordovaPlugin.java | 2 +- www/js/newrelic.js | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/android/NewRelicCordovaPlugin.java b/src/android/NewRelicCordovaPlugin.java index e7ae6ec..bc66ee0 100644 --- a/src/android/NewRelicCordovaPlugin.java +++ b/src/android/NewRelicCordovaPlugin.java @@ -232,7 +232,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo exceptionMap.put("isFatal", isFatal); if (attributesAsJson != null) { final Map attributes = new Gson().fromJson(String.valueOf(attributesAsJson), - Map.class); + Map.class); for (String key : attributes.keySet()) { exceptionMap.put(key, attributes.get(key)); } diff --git a/www/js/newrelic.js b/www/js/newrelic.js index 28bc1dd..0720426 100644 --- a/www/js/newrelic.js +++ b/www/js/newrelic.js @@ -145,13 +145,18 @@ cordova.define("newrelic-cordova-plugin.NewRelic", function(require, exports, mo * Records JavaScript errors for Cordova. * @param {Error} err The error to record. * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. - */ - recordError: function(err, attributes={}, cb, fail) { + * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. + */ + recordError: function(err, attributes={}, attributes={}, cb, fail) { let errorAttributes = attributes instanceof Map ? Object.fromEntries(attributes) : attributes; if (attributes === null) { errorAttributes = {}; } - if (err) { + let errorAttributes = attributes instanceof Map ? Object.fromEntries(attributes) : attributes; + if (attributes === null) { + errorAttributes = {}; + } + if (err) { var error; if (err instanceof Error) { @@ -163,7 +168,7 @@ cordova.define("newrelic-cordova-plugin.NewRelic", function(require, exports, mo } if(error !== undefined) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false, errorAttributes]); + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false, errorAttributes, errorAttributes]); } else { window.console.warn('Undefined error in NewRelic.recordError'); } From 79c9ee0007e0d82134b57a0f84f75ba67cf55802 Mon Sep 17 00:00:00 2001 From: mchavez-newrelic <132291725+mchavez-newrelic@users.noreply.github.com> Date: Fri, 14 Jul 2023 07:40:16 -0700 Subject: [PATCH 08/15] Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes --- www/js/newrelic.js | 389 +++++++++++++++++++++------------------------ 1 file changed, 181 insertions(+), 208 deletions(-) diff --git a/www/js/newrelic.js b/www/js/newrelic.js index 0720426..47c200e 100644 --- a/www/js/newrelic.js +++ b/www/js/newrelic.js @@ -147,223 +147,196 @@ cordova.define("newrelic-cordova-plugin.NewRelic", function(require, exports, mo * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. */ - recordError: function(err, attributes={}, attributes={}, cb, fail) { - let errorAttributes = attributes instanceof Map ? Object.fromEntries(attributes) : attributes; - if (attributes === null) { - errorAttributes = {}; - } - let errorAttributes = attributes instanceof Map ? Object.fromEntries(attributes) : attributes; - if (attributes === null) { - errorAttributes = {}; - } + recordError: function(err, cb, fail) { if (err) { - var error; - - if (err instanceof Error) { - error = err; - } - - if (typeof err === 'string') { - error = new Error(err || ''); - } - - if(error !== undefined) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false, errorAttributes, errorAttributes]); - } else { - window.console.warn('Undefined error in NewRelic.recordError'); - } - + var error; + + if (err instanceof Error) { + error = err; + } + + if (typeof err === 'string') { + error = new Error(err || ''); + } + + if(error !== undefined) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false]); } else { - window.console.warn('Error is required in NewRelic.recordError'); + window.console.warn('Undefined error in NewRelic.recordError'); } - }, - - /** - * Throws a demo run-time exception to test New Relic crash reporting. - * @param {string} message An optional argument attached to the exception. - */ - crashNow: function (message = '', cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "crashNow", [message]); - }, - - /** - * Returns the current session ID as a parameter to the successful callback function. - * This method is useful for consolidating monitoring of app data (not just New Relic data) based on a single session definition and identifier. - * @param {function} cb A success callback function. - * @returns {Promise} A promise containing the current session ID. - */ - currentSessionId: function (cb, fail) { - return new Promise(function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "currentSessionId"); - }); - }, - - /** - * Increments the count of an attribute with a specified name. - * When called, it overwrites its previous value and type each time. - * If attribute does not exist, it creates an attribute with a value of 1. - * The incremented attribute is shared by multiple Mobile event types. - * @param {string} name The name of the attribute. - * @param {number} value Optional argument that increments the attribute by this value. - */ - incrementAttribute: function(name, value=1, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "incrementAttribute", [name, value]); - }, - - /** - * Records network failures. - * If a network request fails, use this method to record details about the failure. - * In most cases, place this call inside exception handlers. - * @param {string} url The URL of the request. - * @param {string} httpMethod The HTTP method used, such as GET or POST. - * @param {number} startTime The start time of the request in milliseconds since the epoch. - * @param {number} endTime The end time of the request in milliseconds since the epoch. - * @param {string} failure The name of the network failure. Possible values are 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'. - */ - noticeNetworkFailure: function (url, httpMethod, startTime, endTime, failure, cb, fail) { - const failureNames = new Set(['Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed']); - if (!failureNames.has(failure)) { - window.console.error("NewRelic.noticeNetworkFailure: Network failure name has to be one of: 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'"); + + } else { + window.console.warn('Error is required in NewRelic.recordError'); + } + }, + + /** + * Throws a demo run-time exception to test New Relic crash reporting. + * @param {string} message An optional argument attached to the exception. + */ + crashNow: function (message = '', cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "crashNow", [message]); + }, + + /** + * Returns the current session ID as a parameter to the successful callback function. + * This method is useful for consolidating monitoring of app data (not just New Relic data) based on a single session definition and identifier. + * @param {function} cb A success callback function. + * @returns {Promise} A promise containing the current session ID. + */ + currentSessionId: function (cb, fail) { + return new Promise(function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "currentSessionId"); + }); + }, + + /** + * Increments the count of an attribute with a specified name. + * When called, it overwrites its previous value and type each time. + * If attribute does not exist, it creates an attribute with a value of 1. + * The incremented attribute is shared by multiple Mobile event types. + * @param {string} name The name of the attribute. + * @param {number} value Optional argument that increments the attribute by this value. + */ + incrementAttribute: function(name, value=1, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "incrementAttribute", [name, value]); + }, + + /** + * Records network failures. + * If a network request fails, use this method to record details about the failure. + * In most cases, place this call inside exception handlers. + * @param {string} url The URL of the request. + * @param {string} httpMethod The HTTP method used, such as GET or POST. + * @param {number} startTime The start time of the request in milliseconds since the epoch. + * @param {number} endTime The end time of the request in milliseconds since the epoch. + * @param {string} failure The name of the network failure. Possible values are 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'. + */ + noticeNetworkFailure: function (url, httpMethod, startTime, endTime, failure, cb, fail) { + const failureNames = new Set(['Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed']); + if (!failureNames.has(failure)) { + window.console.error("NewRelic.noticeNetworkFailure: Network failure name has to be one of: 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'"); + return; + } + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeNetworkFailure", [url, httpMethod, startTime, endTime, failure]); + }, + + /** + * + * @param {string} name The name for the custom metric. + * @param {string} category The metric category name. + * @param {number} value Optional. The value of the metric. Value should be a non-zero positive number. + * @param {string} countUnit Optional (but requires value and valueUnit to be set). Unit of measurement for the metric count. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. + * @param {string} valueUnit Optional (but requires value and countUnit to be set). Unit of measurement for the metric value. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. + */ + recordMetric: function (name, category, value = -1, countUnit = null, valueUnit = null, cb, fail) { + const metricUnits = new Set(['PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS']); + if (value < 0) { + if (countUnit !== null || valueUnit !== null) { + window.console.error('NewRelic.recordMetric: value must be set in recordMetric if countUnit and valueUnit are set'); return; } - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeNetworkFailure", [url, httpMethod, startTime, endTime, failure]); - }, - - /** - * - * @param {string} name The name for the custom metric. - * @param {string} category The metric category name. - * @param {number} value Optional. The value of the metric. Value should be a non-zero positive number. - * @param {string} countUnit Optional (but requires value and valueUnit to be set). Unit of measurement for the metric count. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. - * @param {string} valueUnit Optional (but requires value and countUnit to be set). Unit of measurement for the metric value. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. - */ - recordMetric: function (name, category, value = -1, countUnit = null, valueUnit = null, cb, fail) { - const metricUnits = new Set(['PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS']); - if (value < 0) { - if (countUnit !== null || valueUnit !== null) { - window.console.error('NewRelic.recordMetric: value must be set in recordMetric if countUnit and valueUnit are set'); - return; - } - } else { - if ((countUnit !== null && valueUnit == null) || (countUnit == null && valueUnit !== null)) { - window.console.error('NewRelic.recordMetric: countUnit and valueUnit in recordMetric must both be null or set'); + } else { + if ((countUnit !== null && valueUnit == null) || (countUnit == null && valueUnit !== null)) { + window.console.error('NewRelic.recordMetric: countUnit and valueUnit in recordMetric must both be null or set'); + return; + } else if (countUnit !== null && valueUnit !== null) { + if (!metricUnits.has(countUnit) || !metricUnits.has(valueUnit)) { + window.console.error("NewRelic.recordMetric: countUnit or valueUnit in recordMetric has to be one of 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS'"); return; - } else if (countUnit !== null && valueUnit !== null) { - if (!metricUnits.has(countUnit) || !metricUnits.has(valueUnit)) { - window.console.error("NewRelic.recordMetric: countUnit or valueUnit in recordMetric has to be one of 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS'"); - return; - } } } - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordMetric", [name, category, value, countUnit, valueUnit]); - }, - - /** - * Removes all attributes from the session.. - */ - removeAllAttributes: function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "removeAllAttributes"); - }, - - /** - * Sets the event harvest cycle length. - * Default is 600 seconds (10 minutes). - * Minimum value cannot be less than 60 seconds. - * Maximum value should not be greater than 600 seconds. - * @param {number} maxBufferTimeInSeconds The maximum time (in seconds) that the agent should store events in memory. - */ - setMaxEventBufferTime: function (maxBufferTimeInSeconds, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventBufferTime", [maxBufferTimeInSeconds]); - }, - - /** - * Sets the maximum size of the event pool stored in memory until the next harvest cycle. - * When the pool size limit is reached, the agent will start sampling events, discarding some new and old, until the pool of events is sent in the next harvest cycle. - * Default is a maximum of 1000 events per event harvest cycle. - * @param {number} maxPoolSize The maximum number of events per harvest cycle. - */ - setMaxEventPoolSize: function (maxPoolSize, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventPoolSize", [maxPoolSize]); - }, - - /** - * FOR ANDROID ONLY. - * Enable or disable collection of event data. - * @param {boolean} enabled Boolean value for enabling analytics events. - */ - analyticsEventEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "analyticsEventEnabled", [enabled]); - }, - - /** - * Enable or disable reporting sucessful HTTP request to the MobileRequest event type. - * @param {boolean} enabled Boolean value for enable successful HTTP requests. - */ - networkRequestEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkRequestEnabled", [enabled]); - }, - - /** - * Enable or disable reporting network and HTTP request errors to the MobileRequestError event type. - * @param {boolean} enabled Boolean value for enabling network request errors. - */ - networkErrorRequestEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkErrorRequestEnabled", [enabled]); - }, - - /** - * Enable or disable capture of HTTP response bodies for HTTP error traces, and MobileRequestError events. - * @param {boolean} enabled Boolean value for enabling HTTP response bodies. - */ - httpRequestBodyCaptureEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "httpRequestBodyCaptureEnabled", [enabled]); - }, - - /** - * Shut down the agent within the current application lifecycle during runtime. - * Once the agent has shut down, it cannot be restarted within the current application lifecycle. - */ - shutdown: function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "shutdown"); - }, - - addHTTPHeadersTrackingFor: function (headers,cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "addHTTPHeadersTrackingFor",[headers]); - }, - - getHTTPHeadersTrackingFor: function (cb, fail) { - - return new Promise(function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "getHTTPHeadersTrackingFor"); - }); - }, - - generateDistributedTracingHeaders: function (cb, fail) { - - return new Promise(function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "generateDistributedTracingHeaders"); - }); - }, - - } - - networkRequest = {}; - var originalXhrOpen = XMLHttpRequest.prototype.open; - var originalXHRSend = XMLHttpRequest.prototype.send; + } + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordMetric", [name, category, value, countUnit, valueUnit]); + }, - window.XMLHttpRequest.prototype.open = function (method, url) { - // Keep track of the method and url - // start time is tracked by the `send` method - - // eslint-disable-next-line prefer-rest-params - - networkRequest.url = url; - networkRequest.method = method; - networkRequest.bytesSent = 0; - networkRequest.startTime = Date.now(); - return originalXhrOpen.apply(this, arguments) - - } + /** + * Removes all attributes from the session.. + */ + removeAllAttributes: function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "removeAllAttributes"); + }, + + /** + * Sets the event harvest cycle length. + * Default is 600 seconds (10 minutes). + * Minimum value cannot be less than 60 seconds. + * Maximum value should not be greater than 600 seconds. + * @param {number} maxBufferTimeInSeconds The maximum time (in seconds) that the agent should store events in memory. + */ + setMaxEventBufferTime: function (maxBufferTimeInSeconds, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventBufferTime", [maxBufferTimeInSeconds]); + }, + + /** + * Sets the maximum size of the event pool stored in memory until the next harvest cycle. + * When the pool size limit is reached, the agent will start sampling events, discarding some new and old, until the pool of events is sent in the next harvest cycle. + * Default is a maximum of 1000 events per event harvest cycle. + * @param {number} maxPoolSize The maximum number of events per harvest cycle. + */ + setMaxEventPoolSize: function (maxPoolSize, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventPoolSize", [maxPoolSize]); + }, + + /** + * FOR ANDROID ONLY. + * Enable or disable collection of event data. + * @param {boolean} enabled Boolean value for enabling analytics events. + */ + analyticsEventEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "analyticsEventEnabled", [enabled]); + }, + + /** + * Enable or disable reporting sucessful HTTP request to the MobileRequest event type. + * @param {boolean} enabled Boolean value for enable successful HTTP requests. + */ + networkRequestEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkRequestEnabled", [enabled]); + }, + + /** + * Enable or disable reporting network and HTTP request errors to the MobileRequestError event type. + * @param {boolean} enabled Boolean value for enabling network request errors. + */ + networkErrorRequestEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkErrorRequestEnabled", [enabled]); + }, + + /** + * Enable or disable capture of HTTP response bodies for HTTP error traces, and MobileRequestError events. + * @param {boolean} enabled Boolean value for enabling HTTP response bodies. + */ + httpRequestBodyCaptureEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "httpRequestBodyCaptureEnabled", [enabled]); + }, + + /** + * Shut down the agent within the current application lifecycle during runtime. + * Once the agent has shut down, it cannot be restarted within the current application lifecycle. + */ + shutdown: function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "shutdown"); + }, + +} + +networkRequest = {}; +var originalXhrOpen = XMLHttpRequest.prototype.open; +var originalXHRSend = XMLHttpRequest.prototype.send; +window.XMLHttpRequest.prototype.open = function (method, url) { + // Keep track of the method and url + // start time is tracked by the `send` method + + // eslint-disable-next-line prefer-rest-params + + networkRequest.url = url; + networkRequest.method = method; + networkRequest.bytesSent = 0; + networkRequest.startTime = Date.now(); + return originalXhrOpen.apply(this, arguments) + +} window.XMLHttpRequest.prototype.send = function (data) { From 21687fbf37119ff1b2e2d5b6ad304d27ef6f0d14 Mon Sep 17 00:00:00 2001 From: mchavez-newrelic <132291725+mchavez-newrelic@users.noreply.github.com> Date: Fri, 14 Jul 2023 07:40:16 -0700 Subject: [PATCH 09/15] Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes --- www/js/newrelic.js | 278 +++++++++++++++++++++------------------------ 1 file changed, 131 insertions(+), 147 deletions(-) diff --git a/www/js/newrelic.js b/www/js/newrelic.js index 47c200e..ba21486 100644 --- a/www/js/newrelic.js +++ b/www/js/newrelic.js @@ -1,153 +1,137 @@ -cordova.define("newrelic-cordova-plugin.NewRelic", function(require, exports, module) { - /* - * Copyright (c) 2022-present New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 +/* + * Copyright (c) 2022-present New Relic Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +var exec = require("cordova/exec"); + +var NewRelic = { + + /** + * + * @param {string} url The URL of the request. + * @param {string} method The HTTP method used, such as GET or POST. + * @param {number} status The statusCode of the HTTP response, such as 200 for OK. + * @param {number} startTime The start time of the request in milliseconds since the epoch. + * @param {number} endTime The end time of the request in milliseconds since the epoch. + * @param {number} bytesSent The number of bytes sent in the request. + * @param {number} bytesReceived The number of bytes received in the response. + * @param {string} body Optional. The response body of the HTTP response. The response body will be truncated and included in an HTTP Error metric if the HTTP transaction is an error. */ + noticeHttpTransaction: function (url, method, status, startTime, endTime, bytesSent, bytesReceived, body, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeHttpTransaction", [url, method, status, startTime, endTime, bytesSent, bytesReceived, body]); + }, + + noticeDistributedTrace: function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeDistributedTrace"); + }, - var exec = require("cordova/exec"); - - var NewRelic = { - - /** - * - * @param {string} url The URL of the request. - * @param {string} method The HTTP method used, such as GET or POST. - * @param {number} status The statusCode of the HTTP response, such as 200 for OK. - * @param {number} startTime The start time of the request in milliseconds since the epoch. - * @param {number} endTime The end time of the request in milliseconds since the epoch. - * @param {number} bytesSent The number of bytes sent in the request. - * @param {number} bytesReceived The number of bytes received in the response. - * @param {string} body Optional. The response body of the HTTP response. The response body will be truncated and included in an HTTP Error metric if the HTTP transaction is an error. - */ - noticeHttpTransaction: function (url, method, status, startTime, endTime, bytesSent, bytesReceived, body,params,traceAttributes, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeHttpTransaction", [url, method, status, startTime, endTime, bytesSent, bytesReceived, body,params,traceAttributes]); - }, - - noticeDistributedTrace: function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeDistributedTrace"); - }, - - /** - * Sets a custom user identifier value to associate mobile user - * @param {string} userId The user identifier string. - */ - setUserId: function (userId, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setUserId", [userId]); - }, - - /** - * Creates a custom attribute with a specified name and value. - * When called, it overwrites its previous value and type. - * The created attribute is shared by multiple Mobile event types. - * @param {string} attributeName Name of the attribute. - * @param {number} value Value of the attribute. - */ - setAttribute: function (attributeName, value, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setAttribute", [attributeName, value]); - }, - - /** - * Remove a custom attribute with a specified name and value. - * When called, it removes the attribute specified by the name string. - * The removed attribute is shared by multiple Mobile event types. - * @param {string} name Name of the attribute. - */ - removeAttribute: function (name, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "removeAttribute", [name]); - }, - - /** - * Creates and records a MobileBreadcrumb event. - * @param {string} eventName The name you want to give to a breadcrumb event. - * @param {Map} attributes A map that includes a list of attributes. - */ - recordBreadcrumb: function (eventName, attributes, cb, fail) { - const crumb = new BreadCrumb({ eventName, attributes }); - crumb.attributes.isValid(() => { - crumb.eventName.isValid(() => { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordBreadCrumb", [eventName, crumb.attributes.value]); - }); - }); - }, - - /** - * Creates and records a custom event, for use in New Relic Insights. - * The event includes a list of attributes, specified as a map. - * @param {string} eventType The type of event. - * @param {string} eventName The name of the event. - * @param {Map} attributes A map that includes a list of attributes. - */ - recordCustomEvent: function (eventType, eventName, attributes, cb, fail) { - const customEvent = new NewRelicEvent({ eventType, eventName, attributes }); - customEvent.attributes.isValid(() => { - if (customEvent.eventName.isValid() && customEvent.eventType.isValid()) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordCustomEvent", [eventType, eventName, customEvent.attributes.value]); - } else { - window.console.error("Invalid event name or type in recordCustomEvent"); - } - }); - }, - - /** - * Creates and records log as custom Events, for use in New Relic Insights. - * The event includes a list of attributes, specified as a map. - * @param {string} eventType The type of event. - * @param {string} eventName The name of the event. - * @param {Map} attributes A map that includes a list of attributes. - */ - recordLogs: function (eventType, eventName, attributes, cb, fail) { - const customEvent = new NewRelicEvent({ eventType, eventName, attributes }); - customEvent.attributes.isValid(() => { - if (customEvent.eventName.isValid() && customEvent.eventType.isValid()) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordLogs", [eventType, eventName, customEvent.attributes.value]); - } else { - window.console.error("Invalid event name or type in recordCustomEvent"); - } - }); - }, - - /** - * Track a method as an interaction. - * @param {string} actionName The name of the action. - * @param {function} cb A success callback function. - * @returns {Promise} A promise containing the interactionId. - */ - startInteraction: function (actionName, cb, fail) { - return new Promise(function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "startInteraction", [actionName]); - }); - }, - - /** - * End an interaction - * @param {string} interactionId The string ID for the interaction you want to end. This string is returned when you use startInteraction(). - */ - endInteraction: function (interactionId, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "endInteraction", [interactionId]); - }, - - sendConsole(type, args) { - const argsStr = JSON.stringify(args, getCircularReplacer()); - this.send('MobileJSConsole', { consoleType: type, args: argsStr }); - }, - - send(name, args) { - const nameStr = String(name); - const argsStr = {}; - Object.keys(args).forEach(key => { - argsStr[String(key)] = String(args[key]); + /** + * Sets a custom user identifier value to associate mobile user + * @param {string} userId The user identifier string. + */ + setUserId: function (userId, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setUserId", [userId]); + }, + + /** + * Creates a custom attribute with a specified name and value. + * When called, it overwrites its previous value and type. + * The created attribute is shared by multiple Mobile event types. + * @param {string} attributeName Name of the attribute. + * @param {number} value Value of the attribute. + */ + setAttribute: function (attributeName, value, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setAttribute", [attributeName, value]); + }, + + /** + * Remove a custom attribute with a specified name and value. + * When called, it removes the attribute specified by the name string. + * The removed attribute is shared by multiple Mobile event types. + * @param {string} name Name of the attribute. + */ + removeAttribute: function (name, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "removeAttribute", [name]); + }, + + /** + * Creates and records a MobileBreadcrumb event. + * @param {string} eventName The name you want to give to a breadcrumb event. + * @param {Map} attributes A map that includes a list of attributes. + */ + recordBreadcrumb: function (eventName, attributes, cb, fail) { + const crumb = new BreadCrumb({ eventName, attributes }); + crumb.attributes.isValid(() => { + crumb.eventName.isValid(() => { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordBreadCrumb", [eventName, crumb.attributes.value]); }); - - this.recordLogs("consoleEvents", name, args); - }, - - /** - * Records JavaScript errors for Cordova. - * @param {Error} err The error to record. - * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. - * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. + }); + }, + + /** + * Creates and records a custom event, for use in New Relic Insights. + * The event includes a list of attributes, specified as a map. + * @param {string} eventType The type of event. + * @param {string} eventName The name of the event. + * @param {Map} attributes A map that includes a list of attributes. + */ + recordCustomEvent: function (eventType, eventName, attributes, cb, fail) { + const customEvent = new NewRelicEvent({ eventType, eventName, attributes }); + customEvent.attributes.isValid(() => { + if (customEvent.eventName.isValid() && customEvent.eventType.isValid()) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordCustomEvent", [eventType, eventName, customEvent.attributes.value]); + } else { + window.console.error("Invalid event name or type in recordCustomEvent"); + } + }); + }, + + /** + * Track a method as an interaction. + * @param {string} actionName The name of the action. + * @param {function} cb A success callback function. + * @returns {Promise} A promise containing the interactionId. + */ + startInteraction: function (actionName, cb, fail) { + return new Promise(function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "startInteraction", [actionName]); + }); + }, + + /** + * End an interaction + * @param {string} interactionId The string ID for the interaction you want to end. This string is returned when you use startInteraction(). */ - recordError: function(err, cb, fail) { + endInteraction: function (interactionId, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "endInteraction", [interactionId]); + }, + + sendConsole(type, args) { + const argsStr = JSON.stringify(args, getCircularReplacer()); + this.send('MobileJSConsole', { consoleType: type, args: argsStr }); + }, + + send(name, args) { + const nameStr = String(name); + const argsStr = {}; + Object.keys(args).forEach(key => { + argsStr[String(key)] = String(args[key]); + }); + + this.recordCustomEvent("consoleEvents", name, args); + }, + + /** + * Records JavaScript errors for Cordova. + * @param {Error} err The error to record. + * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. + */ + recordError: function(err, attributes={}, cb, fail) { + let errorAttributes = attributes instanceof Map ? Object.fromEntries(attributes) : attributes; + if (attributes === null) { + errorAttributes = {}; + } if (err) { var error; @@ -160,7 +144,7 @@ cordova.define("newrelic-cordova-plugin.NewRelic", function(require, exports, mo } if(error !== undefined) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false]); + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false, errorAttributes]); } else { window.console.warn('Undefined error in NewRelic.recordError'); } From bf2df2cae217477f1d822cda82847c9357282c76 Mon Sep 17 00:00:00 2001 From: ndesai-newrelic Date: Tue, 13 Feb 2024 13:45:17 -0600 Subject: [PATCH 10/15] resolve merge conflicts with master --- src/android/NewRelicCordovaPlugin.java | 2 +- www/js/newrelic.js | 351 +++++++++++++------------ 2 files changed, 186 insertions(+), 167 deletions(-) diff --git a/src/android/NewRelicCordovaPlugin.java b/src/android/NewRelicCordovaPlugin.java index bc66ee0..e7ae6ec 100644 --- a/src/android/NewRelicCordovaPlugin.java +++ b/src/android/NewRelicCordovaPlugin.java @@ -232,7 +232,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo exceptionMap.put("isFatal", isFatal); if (attributesAsJson != null) { final Map attributes = new Gson().fromJson(String.valueOf(attributesAsJson), - Map.class); + Map.class); for (String key : attributes.keySet()) { exceptionMap.put(key, attributes.get(key)); } diff --git a/www/js/newrelic.js b/www/js/newrelic.js index ba21486..7b46319 100644 --- a/www/js/newrelic.js +++ b/www/js/newrelic.js @@ -135,192 +135,211 @@ var NewRelic = { if (err) { var error; - if (err instanceof Error) { - error = err; - } + if (err instanceof Error) { + error = err; + } - if (typeof err === 'string') { - error = new Error(err || ''); - } + if (typeof err === 'string') { + error = new Error(err || ''); + } if(error !== undefined) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false, errorAttributes]); + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false]); } else { window.console.warn('Undefined error in NewRelic.recordError'); } - } else { - window.console.warn('Error is required in NewRelic.recordError'); - } - }, - - /** - * Throws a demo run-time exception to test New Relic crash reporting. - * @param {string} message An optional argument attached to the exception. - */ - crashNow: function (message = '', cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "crashNow", [message]); - }, - - /** - * Returns the current session ID as a parameter to the successful callback function. - * This method is useful for consolidating monitoring of app data (not just New Relic data) based on a single session definition and identifier. - * @param {function} cb A success callback function. - * @returns {Promise} A promise containing the current session ID. - */ - currentSessionId: function (cb, fail) { - return new Promise(function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "currentSessionId"); - }); - }, - - /** - * Increments the count of an attribute with a specified name. - * When called, it overwrites its previous value and type each time. - * If attribute does not exist, it creates an attribute with a value of 1. - * The incremented attribute is shared by multiple Mobile event types. - * @param {string} name The name of the attribute. - * @param {number} value Optional argument that increments the attribute by this value. - */ - incrementAttribute: function(name, value=1, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "incrementAttribute", [name, value]); - }, - - /** - * Records network failures. - * If a network request fails, use this method to record details about the failure. - * In most cases, place this call inside exception handlers. - * @param {string} url The URL of the request. - * @param {string} httpMethod The HTTP method used, such as GET or POST. - * @param {number} startTime The start time of the request in milliseconds since the epoch. - * @param {number} endTime The end time of the request in milliseconds since the epoch. - * @param {string} failure The name of the network failure. Possible values are 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'. - */ - noticeNetworkFailure: function (url, httpMethod, startTime, endTime, failure, cb, fail) { - const failureNames = new Set(['Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed']); - if (!failureNames.has(failure)) { - window.console.error("NewRelic.noticeNetworkFailure: Network failure name has to be one of: 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'"); - return; - } - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeNetworkFailure", [url, httpMethod, startTime, endTime, failure]); - }, - - /** - * - * @param {string} name The name for the custom metric. - * @param {string} category The metric category name. - * @param {number} value Optional. The value of the metric. Value should be a non-zero positive number. - * @param {string} countUnit Optional (but requires value and valueUnit to be set). Unit of measurement for the metric count. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. - * @param {string} valueUnit Optional (but requires value and countUnit to be set). Unit of measurement for the metric value. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. - */ - recordMetric: function (name, category, value = -1, countUnit = null, valueUnit = null, cb, fail) { - const metricUnits = new Set(['PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS']); - if (value < 0) { - if (countUnit !== null || valueUnit !== null) { - window.console.error('NewRelic.recordMetric: value must be set in recordMetric if countUnit and valueUnit are set'); - return; + } else { + window.console.warn('Error is required in NewRelic.recordError'); } - } else { - if ((countUnit !== null && valueUnit == null) || (countUnit == null && valueUnit !== null)) { - window.console.error('NewRelic.recordMetric: countUnit and valueUnit in recordMetric must both be null or set'); + }, + + /** + * Throws a demo run-time exception to test New Relic crash reporting. + * @param {string} message An optional argument attached to the exception. + */ + crashNow: function (message = '', cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "crashNow", [message]); + }, + + /** + * Returns the current session ID as a parameter to the successful callback function. + * This method is useful for consolidating monitoring of app data (not just New Relic data) based on a single session definition and identifier. + * @param {function} cb A success callback function. + * @returns {Promise} A promise containing the current session ID. + */ + currentSessionId: function (cb, fail) { + return new Promise(function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "currentSessionId"); + }); + }, + + /** + * Increments the count of an attribute with a specified name. + * When called, it overwrites its previous value and type each time. + * If attribute does not exist, it creates an attribute with a value of 1. + * The incremented attribute is shared by multiple Mobile event types. + * @param {string} name The name of the attribute. + * @param {number} value Optional argument that increments the attribute by this value. + */ + incrementAttribute: function(name, value=1, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "incrementAttribute", [name, value]); + }, + + /** + * Records network failures. + * If a network request fails, use this method to record details about the failure. + * In most cases, place this call inside exception handlers. + * @param {string} url The URL of the request. + * @param {string} httpMethod The HTTP method used, such as GET or POST. + * @param {number} startTime The start time of the request in milliseconds since the epoch. + * @param {number} endTime The end time of the request in milliseconds since the epoch. + * @param {string} failure The name of the network failure. Possible values are 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'. + */ + noticeNetworkFailure: function (url, httpMethod, startTime, endTime, failure, cb, fail) { + const failureNames = new Set(['Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed']); + if (!failureNames.has(failure)) { + window.console.error("NewRelic.noticeNetworkFailure: Network failure name has to be one of: 'Unknown', 'BadURL', 'TimedOut', 'CannotConnectToHost', 'DNSLookupFailed', 'BadServerResponse', 'SecureConnectionFailed'"); return; - } else if (countUnit !== null && valueUnit !== null) { - if (!metricUnits.has(countUnit) || !metricUnits.has(valueUnit)) { - window.console.error("NewRelic.recordMetric: countUnit or valueUnit in recordMetric has to be one of 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS'"); + } + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeNetworkFailure", [url, httpMethod, startTime, endTime, failure]); + }, + + /** + * + * @param {string} name The name for the custom metric. + * @param {string} category The metric category name. + * @param {number} value Optional. The value of the metric. Value should be a non-zero positive number. + * @param {string} countUnit Optional (but requires value and valueUnit to be set). Unit of measurement for the metric count. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. + * @param {string} valueUnit Optional (but requires value and countUnit to be set). Unit of measurement for the metric value. Supported values are 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', or 'OPERATIONS'. + */ + recordMetric: function (name, category, value = -1, countUnit = null, valueUnit = null, cb, fail) { + const metricUnits = new Set(['PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS']); + if (value < 0) { + if (countUnit !== null || valueUnit !== null) { + window.console.error('NewRelic.recordMetric: value must be set in recordMetric if countUnit and valueUnit are set'); return; } + } else { + if ((countUnit !== null && valueUnit == null) || (countUnit == null && valueUnit !== null)) { + window.console.error('NewRelic.recordMetric: countUnit and valueUnit in recordMetric must both be null or set'); + return; + } else if (countUnit !== null && valueUnit !== null) { + if (!metricUnits.has(countUnit) || !metricUnits.has(valueUnit)) { + window.console.error("NewRelic.recordMetric: countUnit or valueUnit in recordMetric has to be one of 'PERCENT', 'BYTES', 'SECONDS', 'BYTES_PER_SECOND', 'OPERATIONS'"); + return; + } + } } - } - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordMetric", [name, category, value, countUnit, valueUnit]); - }, - - /** - * Removes all attributes from the session.. - */ - removeAllAttributes: function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "removeAllAttributes"); - }, - - /** - * Sets the event harvest cycle length. - * Default is 600 seconds (10 minutes). - * Minimum value cannot be less than 60 seconds. - * Maximum value should not be greater than 600 seconds. - * @param {number} maxBufferTimeInSeconds The maximum time (in seconds) that the agent should store events in memory. - */ - setMaxEventBufferTime: function (maxBufferTimeInSeconds, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventBufferTime", [maxBufferTimeInSeconds]); - }, - - /** - * Sets the maximum size of the event pool stored in memory until the next harvest cycle. - * When the pool size limit is reached, the agent will start sampling events, discarding some new and old, until the pool of events is sent in the next harvest cycle. - * Default is a maximum of 1000 events per event harvest cycle. - * @param {number} maxPoolSize The maximum number of events per harvest cycle. - */ - setMaxEventPoolSize: function (maxPoolSize, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventPoolSize", [maxPoolSize]); - }, - - /** - * FOR ANDROID ONLY. - * Enable or disable collection of event data. - * @param {boolean} enabled Boolean value for enabling analytics events. - */ - analyticsEventEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "analyticsEventEnabled", [enabled]); - }, - - /** - * Enable or disable reporting sucessful HTTP request to the MobileRequest event type. - * @param {boolean} enabled Boolean value for enable successful HTTP requests. - */ - networkRequestEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkRequestEnabled", [enabled]); - }, + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordMetric", [name, category, value, countUnit, valueUnit]); + }, + + /** + * Removes all attributes from the session.. + */ + removeAllAttributes: function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "removeAllAttributes"); + }, + + /** + * Sets the event harvest cycle length. + * Default is 600 seconds (10 minutes). + * Minimum value cannot be less than 60 seconds. + * Maximum value should not be greater than 600 seconds. + * @param {number} maxBufferTimeInSeconds The maximum time (in seconds) that the agent should store events in memory. + */ + setMaxEventBufferTime: function (maxBufferTimeInSeconds, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventBufferTime", [maxBufferTimeInSeconds]); + }, + + /** + * Sets the maximum size of the event pool stored in memory until the next harvest cycle. + * When the pool size limit is reached, the agent will start sampling events, discarding some new and old, until the pool of events is sent in the next harvest cycle. + * Default is a maximum of 1000 events per event harvest cycle. + * @param {number} maxPoolSize The maximum number of events per harvest cycle. + */ + setMaxEventPoolSize: function (maxPoolSize, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventPoolSize", [maxPoolSize]); + }, + + /** + * FOR ANDROID ONLY. + * Enable or disable collection of event data. + * @param {boolean} enabled Boolean value for enabling analytics events. + */ + analyticsEventEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "analyticsEventEnabled", [enabled]); + }, + + /** + * Enable or disable reporting sucessful HTTP request to the MobileRequest event type. + * @param {boolean} enabled Boolean value for enable successful HTTP requests. + */ + networkRequestEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkRequestEnabled", [enabled]); + }, + + /** + * Enable or disable reporting network and HTTP request errors to the MobileRequestError event type. + * @param {boolean} enabled Boolean value for enabling network request errors. + */ + networkErrorRequestEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkErrorRequestEnabled", [enabled]); + }, + + /** + * Enable or disable capture of HTTP response bodies for HTTP error traces, and MobileRequestError events. + * @param {boolean} enabled Boolean value for enabling HTTP response bodies. + */ + httpRequestBodyCaptureEnabled: function (enabled, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "httpRequestBodyCaptureEnabled", [enabled]); + }, + + /** + * Shut down the agent within the current application lifecycle during runtime. + * Once the agent has shut down, it cannot be restarted within the current application lifecycle. + */ + shutdown: function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "shutdown"); + }, + + addHTTPHeadersTrackingFor: function (headers,cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "addHTTPHeadersTrackingFor",[headers]); + }, + + getHTTPHeadersTrackingFor: function (cb, fail) { + + return new Promise(function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "getHTTPHeadersTrackingFor"); + }); + }, - /** - * Enable or disable reporting network and HTTP request errors to the MobileRequestError event type. - * @param {boolean} enabled Boolean value for enabling network request errors. - */ - networkErrorRequestEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkErrorRequestEnabled", [enabled]); - }, + generateDistributedTracingHeaders: function (cb, fail) { - /** - * Enable or disable capture of HTTP response bodies for HTTP error traces, and MobileRequestError events. - * @param {boolean} enabled Boolean value for enabling HTTP response bodies. - */ - httpRequestBodyCaptureEnabled: function (enabled, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "httpRequestBodyCaptureEnabled", [enabled]); - }, + return new Promise(function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "generateDistributedTracingHeaders"); + }); + }, - /** - * Shut down the agent within the current application lifecycle during runtime. - * Once the agent has shut down, it cannot be restarted within the current application lifecycle. - */ - shutdown: function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "shutdown"); - }, + } -} + networkRequest = {}; + var originalXhrOpen = XMLHttpRequest.prototype.open; + var originalXHRSend = XMLHttpRequest.prototype.send; -networkRequest = {}; -var originalXhrOpen = XMLHttpRequest.prototype.open; -var originalXHRSend = XMLHttpRequest.prototype.send; -window.XMLHttpRequest.prototype.open = function (method, url) { - // Keep track of the method and url - // start time is tracked by the `send` method + window.XMLHttpRequest.prototype.open = function (method, url) { + // Keep track of the method and url + // start time is tracked by the `send` method - // eslint-disable-next-line prefer-rest-params + // eslint-disable-next-line prefer-rest-params - networkRequest.url = url; - networkRequest.method = method; - networkRequest.bytesSent = 0; - networkRequest.startTime = Date.now(); - return originalXhrOpen.apply(this, arguments) + networkRequest.url = url; + networkRequest.method = method; + networkRequest.bytesSent = 0; + networkRequest.startTime = Date.now(); + return originalXhrOpen.apply(this, arguments) -} + } window.XMLHttpRequest.prototype.send = function (data) { From d98ee2d631abbc7e9bd38213a29fe0c032742cd1 Mon Sep 17 00:00:00 2001 From: ndesai Date: Tue, 5 Mar 2024 08:28:30 -0600 Subject: [PATCH 11/15] merge with master --- www/js/newrelic.js | 308 +++++++++++++++++++++++++-------------------- 1 file changed, 171 insertions(+), 137 deletions(-) diff --git a/www/js/newrelic.js b/www/js/newrelic.js index 100bc5c..a4a716c 100644 --- a/www/js/newrelic.js +++ b/www/js/newrelic.js @@ -1,139 +1,157 @@ -/* - * Copyright (c) 2022-present New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -var exec = require("cordova/exec"); - -var NewRelic = { - - /** - * - * @param {string} url The URL of the request. - * @param {string} method The HTTP method used, such as GET or POST. - * @param {number} status The statusCode of the HTTP response, such as 200 for OK. - * @param {number} startTime The start time of the request in milliseconds since the epoch. - * @param {number} endTime The end time of the request in milliseconds since the epoch. - * @param {number} bytesSent The number of bytes sent in the request. - * @param {number} bytesReceived The number of bytes received in the response. - * @param {string} body Optional. The response body of the HTTP response. The response body will be truncated and included in an HTTP Error metric if the HTTP transaction is an error. + /* + * Copyright (c) 2022-present New Relic Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 */ - noticeHttpTransaction: function (url, method, status, startTime, endTime, bytesSent, bytesReceived, body, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeHttpTransaction", [url, method, status, startTime, endTime, bytesSent, bytesReceived, body]); - }, - - noticeDistributedTrace: function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeDistributedTrace"); - }, - /** - * Sets a custom user identifier value to associate mobile user - * @param {string} userId The user identifier string. - */ - setUserId: function (userId, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setUserId", [userId]); - }, - - /** - * Creates a custom attribute with a specified name and value. - * When called, it overwrites its previous value and type. - * The created attribute is shared by multiple Mobile event types. - * @param {string} attributeName Name of the attribute. - * @param {number} value Value of the attribute. - */ - setAttribute: function (attributeName, value, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setAttribute", [attributeName, value]); - }, - - /** - * Remove a custom attribute with a specified name and value. - * When called, it removes the attribute specified by the name string. - * The removed attribute is shared by multiple Mobile event types. - * @param {string} name Name of the attribute. - */ - removeAttribute: function (name, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "removeAttribute", [name]); - }, - - /** - * Creates and records a MobileBreadcrumb event. - * @param {string} eventName The name you want to give to a breadcrumb event. - * @param {Map} attributes A map that includes a list of attributes. - */ - recordBreadcrumb: function (eventName, attributes, cb, fail) { - const crumb = new BreadCrumb({ eventName, attributes }); - crumb.attributes.isValid(() => { - crumb.eventName.isValid(() => { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordBreadCrumb", [eventName, crumb.attributes.value]); + var exec = require("cordova/exec"); + + var NewRelic = { + + /** + * + * @param {string} url The URL of the request. + * @param {string} method The HTTP method used, such as GET or POST. + * @param {number} status The statusCode of the HTTP response, such as 200 for OK. + * @param {number} startTime The start time of the request in milliseconds since the epoch. + * @param {number} endTime The end time of the request in milliseconds since the epoch. + * @param {number} bytesSent The number of bytes sent in the request. + * @param {number} bytesReceived The number of bytes received in the response. + * @param {string} body Optional. The response body of the HTTP response. The response body will be truncated and included in an HTTP Error metric if the HTTP transaction is an error. + */ + noticeHttpTransaction: function (url, method, status, startTime, endTime, bytesSent, bytesReceived, body,params,traceAttributes, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeHttpTransaction", [url, method, status, startTime, endTime, bytesSent, bytesReceived, body,params,traceAttributes]); + }, + + noticeDistributedTrace: function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "noticeDistributedTrace"); + }, + + /** + * Sets a custom user identifier value to associate mobile user + * @param {string} userId The user identifier string. + */ + setUserId: function (userId, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setUserId", [userId]); + }, + + /** + * Creates a custom attribute with a specified name and value. + * When called, it overwrites its previous value and type. + * The created attribute is shared by multiple Mobile event types. + * @param {string} attributeName Name of the attribute. + * @param {number} value Value of the attribute. + */ + setAttribute: function (attributeName, value, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setAttribute", [attributeName, value]); + }, + + /** + * Remove a custom attribute with a specified name and value. + * When called, it removes the attribute specified by the name string. + * The removed attribute is shared by multiple Mobile event types. + * @param {string} name Name of the attribute. + */ + removeAttribute: function (name, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "removeAttribute", [name]); + }, + + /** + * Creates and records a MobileBreadcrumb event. + * @param {string} eventName The name you want to give to a breadcrumb event. + * @param {Map} attributes A map that includes a list of attributes. + */ + recordBreadcrumb: function (eventName, attributes, cb, fail) { + const crumb = new BreadCrumb({ eventName, attributes }); + crumb.attributes.isValid(() => { + crumb.eventName.isValid(() => { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordBreadCrumb", [eventName, crumb.attributes.value]); + }); }); - }); - }, - - /** - * Creates and records a custom event, for use in New Relic Insights. - * The event includes a list of attributes, specified as a map. - * @param {string} eventType The type of event. - * @param {string} eventName The name of the event. - * @param {Map} attributes A map that includes a list of attributes. - */ - recordCustomEvent: function (eventType, eventName, attributes, cb, fail) { - const customEvent = new NewRelicEvent({ eventType, eventName, attributes }); - customEvent.attributes.isValid(() => { - if (customEvent.eventName.isValid() && customEvent.eventType.isValid()) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordCustomEvent", [eventType, eventName, customEvent.attributes.value]); - } else { - window.console.error("Invalid event name or type in recordCustomEvent"); + }, + + /** + * Creates and records a custom event, for use in New Relic Insights. + * The event includes a list of attributes, specified as a map. + * @param {string} eventType The type of event. + * @param {string} eventName The name of the event. + * @param {Map} attributes A map that includes a list of attributes. + */ + recordCustomEvent: function (eventType, eventName, attributes, cb, fail) { + const customEvent = new NewRelicEvent({ eventType, eventName, attributes }); + customEvent.attributes.isValid(() => { + if (customEvent.eventName.isValid() && customEvent.eventType.isValid()) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordCustomEvent", [eventType, eventName, customEvent.attributes.value]); + } else { + window.console.error("Invalid event name or type in recordCustomEvent"); + } + }); + }, + + /** + * Creates and records log as custom Events, for use in New Relic Insights. + * The event includes a list of attributes, specified as a map. + * @param {string} eventType The type of event. + * @param {string} eventName The name of the event. + * @param {Map} attributes A map that includes a list of attributes. + */ + recordLogs: function (eventType, eventName, attributes, cb, fail) { + const customEvent = new NewRelicEvent({ eventType, eventName, attributes }); + customEvent.attributes.isValid(() => { + if (customEvent.eventName.isValid() && customEvent.eventType.isValid()) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordLogs", [eventType, eventName, customEvent.attributes.value]); + } else { + window.console.error("Invalid event name or type in recordCustomEvent"); + } + }); + }, + + /** + * Track a method as an interaction. + * @param {string} actionName The name of the action. + * @param {function} cb A success callback function. + * @returns {Promise} A promise containing the interactionId. + */ + startInteraction: function (actionName, cb, fail) { + return new Promise(function (cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "startInteraction", [actionName]); + }); + }, + + /** + * End an interaction + * @param {string} interactionId The string ID for the interaction you want to end. This string is returned when you use startInteraction(). + */ + endInteraction: function (interactionId, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "endInteraction", [interactionId]); + }, + + sendConsole(type, args) { + const argsStr = JSON.stringify(args, getCircularReplacer()); + this.send('MobileJSConsole', { consoleType: type, args: argsStr }); + }, + + send(name, args) { + const nameStr = String(name); + const argsStr = {}; + Object.keys(args).forEach(key => { + argsStr[String(key)] = String(args[key]); + }); + + this.recordLogs("consoleEvents", name, args); + }, + + /** + * Records JavaScript errors for Cordova. + * @param {Error} err The error to record. + * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. + */ + recordError: function(err, attributes={}, cb, fail) { + let errorAttributes = attributes instanceof Map ? Object.fromEntries(attributes) : attributes; + if (attributes === null) { + errorAttributes = {}; } - }); - }, - - /** - * Track a method as an interaction. - * @param {string} actionName The name of the action. - * @param {function} cb A success callback function. - * @returns {Promise} A promise containing the interactionId. - */ - startInteraction: function (actionName, cb, fail) { - return new Promise(function (cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "startInteraction", [actionName]); - }); - }, - - /** - * End an interaction - * @param {string} interactionId The string ID for the interaction you want to end. This string is returned when you use startInteraction(). - */ - endInteraction: function (interactionId, cb, fail) { - cordova.exec(cb, fail, "NewRelicCordovaPlugin", "endInteraction", [interactionId]); - }, - - sendConsole(type, args) { - const argsStr = JSON.stringify(args, getCircularReplacer()); - this.send('MobileJSConsole', { consoleType: type, args: argsStr }); - }, - - send(name, args) { - const nameStr = String(name); - const argsStr = {}; - Object.keys(args).forEach(key => { - argsStr[String(key)] = String(args[key]); - }); - - this.recordCustomEvent("consoleEvents", name, args); - }, - - /** - * Records JavaScript errors for Cordova. - * @param {Error} err The error to record. - * @param {Map} attributes Optional attributes that will be appended to the handled exception event created in insights. - */ - recordError: function(err, attributes={}, cb, fail) { - let errorAttributes = attributes instanceof Map ? Object.fromEntries(attributes) : attributes; - if (attributes === null) { - errorAttributes = {}; - } - if (err) { - var error; + if (err) { + var error; if (err instanceof Error) { error = err; @@ -142,13 +160,13 @@ var NewRelic = { if (typeof err === 'string') { error = new Error(err || ''); } - + if(error !== undefined) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "recordError", [error.name, error.message, error.stack, false, errorAttributes]); } else { window.console.warn('Undefined error in NewRelic.recordError'); } - + } else { window.console.warn('Error is required in NewRelic.recordError'); } @@ -383,7 +401,9 @@ var NewRelic = { networkRequest.body = ""; } + if(isValidURL(networkRequest.url)) { NewRelic.noticeHttpTransaction(networkRequest.url, networkRequest.method, networkRequest.status, networkRequest.startTime, networkRequest.endTime, networkRequest.bytesSent, networkRequest.bytesreceived, networkRequest.body,networkRequest.params); + } } }, false @@ -460,7 +480,10 @@ var NewRelic = { } }); } else { - options = {headers:{}}; + if(options === undefined) { + options = {}; + } + options['headers'] = {}; options.headers['newrelic'] = headers['newrelic']; options.headers['traceparent'] = headers['traceparent']; options.headers['tracestate'] = headers['tracestate']; @@ -495,6 +518,8 @@ var NewRelic = { function handleFetchSuccess(response, method, url, startTime,headers,params) { response.text().then((v)=>{ + + if(isValidURL(url)) { NewRelic.noticeHttpTransaction( url, method, @@ -507,9 +532,19 @@ var NewRelic = { params, headers ); + } }); } + + function isValidURL(url) { + try { + const newUrl = new URL(url); + return newUrl.protocol === 'http:' || newUrl.protocol === 'https:'; + } catch (err) { + return false; + } + } const defaultLog = window.console.log; const defaultWarn = window.console.warn; @@ -647,5 +682,4 @@ var NewRelic = { module.exports = NewRelic; - }); - + \ No newline at end of file From af05f93de92da954f5528baa0fed12a19b2fc8f2 Mon Sep 17 00:00:00 2001 From: ndesai-newrelic <89222514+ndesai-newrelic@users.noreply.github.com> Date: Tue, 5 Mar 2024 10:30:22 -0600 Subject: [PATCH 12/15] Release 6.2.6 (#83) * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * Update iOS agent to 7.4.6 (#73) * Update iOS Version to 7.4.6 * Release 6.2.3 --------- Co-authored-by: ndesai-newrelic Co-authored-by: ndesai-newrelic <89222514+ndesai-newrelic@users.noreply.github.com> * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * resolve merge conflicts with master * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * resolve merge conflicts with master * merge with master * feature: added offline storage functionality for cordova --------- Co-authored-by: mchavez-newrelic <132291725+mchavez-newrelic@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: ndesai-newrelic --- CHANGELOG.md | 9 +++++++-- README.md | 8 ++++++++ plugin.xml | 9 ++++++--- src/android/NewRelicCordovaPlugin.java | 8 ++++++++ src/ios/NewRelicCordovaPlugin.h | 2 ++ src/ios/NewRelicCordovaPlugin.m | 9 +++++++++ www/js/newrelic.js | 21 ++++++++++++++------- 7 files changed, 54 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 785d389..a23afc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,14 @@ # 6.2.6 ### New in this release -* Fixed a bug in the fetch instrumentation where customer options were inadvertently removed when no headers were specified. Now, options will be preserved even when headers are absent. -* Addressed an issue that resulted in app crashes when an invalid URL was encountered in the capacitor plugin. To mitigate this, a valid URL checker has been implemented to ensure that mobilerequest events are created only with valid URLs. +In this release, we are introducing several new features and updates: +* Added Offline Harvesting Feature: This new feature enables the preservation of harvest data that would otherwise be lost when the application lacks an internet connection. The stored harvests will be sent once the internet connection is re-established and the next harvest upload is successful. +* Introduced setMaxOfflineStorageSize API: This new API allows the user to determine the maximum volume of data that can be stored locally. This aids in better management and control of local data storage. +* Updated native iOS Agent: We've upgraded the native iOS agent to version 7.4.9, which includes performance improvements and bug fixes. +* Updated native Android Agent: We've also upgraded the native Android agent to version 7.3.0 bringing benefits like improved stability and enhanced features. + +These enhancements help to improve overall user experience and application performance. # 6.2.5 diff --git a/README.md b/README.md index 29e76e0..f0b1188 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ Currently, the plugin supports the following agent configuration options: * Possible values are `true` and `false`. Defaults to `false`. * `CONSOLE_LOGS_ENABLED`: Enable or disable reporting javascript console logs as custom events. * Possible values are `true` and `false`. Defaults to `false`. +* `OFFLINE_STORAGE_ENABLED`: Enable or disable offline data storage when no internet connection is available. . + * Possible values are `true` and `false`. Defaults to `true`. # Updating the plugin Update the New Relic Cordova plugin to the latest released version easily via the following command: ``` @@ -211,6 +213,12 @@ Our plugin uses the same APIs as our native agents. See the examples below for u NewRelic.setMaxEventPoolSize(2000); ``` +### [setMaxOfflineStorageSize](https://docs.newrelic.com/docs/mobile-monitoring/new-relic-mobile/mobile-sdk/set-max-offline-storage)(megaBytes: number): void; +> Sets the maximum size of total data that can be stored for offline storage.By default, mobile monitoring can collect a maximum of 100 megaBytes of offline storage. When a data payload fails to send because the device doesn't have an internet connection, it can be stored in the file system until an internet connection has been made. After a typical harvest payload has been successfully sent, all offline data is sent to New Relic and cleared from storage. +```js + NewRelic.setMaxOfflineStorageSize(200); +``` + ### The following methods allow you to set some agent configurations *after* the agent has started: By default, these configurations are already set to true on agent start. diff --git a/plugin.xml b/plugin.xml index a7561ca..1543c74 100644 --- a/plugin.xml +++ b/plugin.xml @@ -18,7 +18,7 @@ - + @@ -29,6 +29,7 @@ + @@ -53,6 +54,7 @@ + @@ -71,7 +73,7 @@ - + @@ -81,7 +83,7 @@ - + @@ -109,6 +111,7 @@ + diff --git a/src/android/NewRelicCordovaPlugin.java b/src/android/NewRelicCordovaPlugin.java index e7ae6ec..b8c17ef 100644 --- a/src/android/NewRelicCordovaPlugin.java +++ b/src/android/NewRelicCordovaPlugin.java @@ -76,6 +76,9 @@ public void initialize(CordovaInterface cordova, CordovaWebView webView) { } if (preferences.getString("default_interactions_enabled", "true").equalsIgnoreCase("false")) { NewRelic.disableFeature(FeatureFlag.DefaultInteractions); + } + if (preferences.getString("offline_storage_enabled", "true").equalsIgnoreCase("true")) { + NewRelic.enableFeature(FeatureFlag.OfflineStorage); } if (preferences.getString("fedramp_enabled", "false").equalsIgnoreCase("true")) { NewRelic.enableFeature(FeatureFlag.FedRampEnabled); @@ -403,6 +406,11 @@ public void run() { NewRelic.setMaxEventBufferTime(maxEventBufferTimeInSeconds); break; } + case "setMaxOfflineStorageSize": { + final int megabytes = args.getInt(0); + NewRelic.setMaxOfflineStorageSize(megabytes); + break; + } case "setMaxEventPoolSize": { final int maxPoolSize = args.getInt(0); NewRelic.setMaxEventPoolSize(maxPoolSize); diff --git a/src/ios/NewRelicCordovaPlugin.h b/src/ios/NewRelicCordovaPlugin.h index 506c509..aaaf8f8 100644 --- a/src/ios/NewRelicCordovaPlugin.h +++ b/src/ios/NewRelicCordovaPlugin.h @@ -49,6 +49,8 @@ - (void)setMaxEventPoolSize:(CDVInvokedUrlCommand *)command; +- (void)setMaxOfflineStorageSize:(CDVInvokedUrlCommand *)command; + - (void)analyticsEventEnabled:(CDVInvokedUrlCommand *) command; - (void)networkRequestEnabled:(CDVInvokedUrlCommand *) command; diff --git a/src/ios/NewRelicCordovaPlugin.m b/src/ios/NewRelicCordovaPlugin.m index 61614c1..95561df 100644 --- a/src/ios/NewRelicCordovaPlugin.m +++ b/src/ios/NewRelicCordovaPlugin.m @@ -55,6 +55,9 @@ - (void)pluginInitialize if (![self shouldDisableFeature:config[@"fedramp_enabled"]]) { [NewRelic enableFeatures:NRFeatureFlag_FedRampEnabled]; } + if (![self shouldDisableFeature:config[@"offline_storage_enabled"]]) { + [NewRelic enableFeatures:NRFeatureFlag_OfflineStorage]; + } // Set log level depending on loggingEnabled and logLevel NRLogLevels logLevel = NRLogLevelWarning; @@ -356,6 +359,12 @@ - (void)setMaxEventPoolSize:(CDVInvokedUrlCommand *)command { [NewRelic setMaxEventPoolSize:uint_maxPoolSize]; } +- (void)setMaxOfflineStorageSize:(CDVInvokedUrlCommand *)command { + NSNumber* megaBytes = [command.arguments objectAtIndex:0]; + unsigned int uint_megaBytes = megaBytes.unsignedIntValue; + [NewRelic setMaxOfflineStorageSize:uint_megaBytes]; +} + - (void)analyticsEventEnabled:(CDVInvokedUrlCommand *)command { // This should only be an android method call, so we do nothing here. return; diff --git a/www/js/newrelic.js b/www/js/newrelic.js index e111fe9..e5d9b98 100644 --- a/www/js/newrelic.js +++ b/www/js/newrelic.js @@ -280,6 +280,14 @@ cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventPoolSize", [maxPoolSize]); }, + /** + * Sets the maximum size of total data that can be stored for offline storage.. + * @param {number} maxPoolSize The Maximum size in megaBytes that can be stored in the file system. + */ + setMaxOfflineStorageSize: function (megaBytes, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxOfflineStorageSize", [megaBytes]); + }, + /** * FOR ANDROID ONLY. * Enable or disable collection of event data. @@ -490,14 +498,14 @@ _arguments[1] = options; } - if(options && 'body' in options) { - networkRequest.bytesSent = options.body.length; + if (options && 'body' in options && options.body !== undefined) { + networkRequest.bytesSent = options.body.length; } else { - networkRequest.bytesSent = 0; + networkRequest.bytesSent = 0; } - - if (networkRequest.method === undefined || networkRequest.method === "" ) { - networkRequest.method = 'GET'; + + if (networkRequest.method === undefined || networkRequest.method === "") { + networkRequest.method = 'GET'; } return new Promise(function (resolve, reject) { // pass through to native fetch @@ -682,4 +690,3 @@ module.exports = NewRelic; - From 832f48602b029a41110a5c97b4147b8ebddaf3da Mon Sep 17 00:00:00 2001 From: ndesai-newrelic <89222514+ndesai-newrelic@users.noreply.github.com> Date: Tue, 20 Feb 2024 10:03:05 -0600 Subject: [PATCH 13/15] Bug fix fetch instrumentation (#82) * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * Update iOS agent to 7.4.6 (#73) * Update iOS Version to 7.4.6 * Release 6.2.3 --------- Co-authored-by: ndesai-newrelic Co-authored-by: ndesai-newrelic <89222514+ndesai-newrelic@users.noreply.github.com> * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * resolve merge conflicts with master * fix fetch instrumentation bugs --------- Co-authored-by: mchavez-newrelic <132291725+mchavez-newrelic@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: ndesai-newrelic --- CHANGELOG.md | 7 +++++++ package.json | 2 +- plugin.xml | 2 +- www/js/newrelic.js | 48 +++++++++++++++++++++------------------------- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c6ed57..785d389 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +# 6.2.6 + +### New in this release +* Fixed a bug in the fetch instrumentation where customer options were inadvertently removed when no headers were specified. Now, options will be preserved even when headers are absent. +* Addressed an issue that resulted in app crashes when an invalid URL was encountered in the capacitor plugin. To mitigate this, a valid URL checker has been implemented to ensure that mobilerequest events are created only with valid URLs. + + # 6.2.5 ### New in this release diff --git a/package.json b/package.json index ee7910c..2e2783c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "newrelic-cordova-plugin", - "version": "6.2.5", + "version": "6.2.6", "description": "New Relic Cordova Plugin for iOS and Android", "repo": "https://github.com/newrelic/newrelic-cordova-plugin/", "scripts": { diff --git a/plugin.xml b/plugin.xml index 2af25cc..a7561ca 100644 --- a/plugin.xml +++ b/plugin.xml @@ -6,7 +6,7 @@ + id="newrelic-cordova-plugin" version="6.2.6"> NewRelic New Relic Cordova Plugin for iOS and Android New Relic diff --git a/www/js/newrelic.js b/www/js/newrelic.js index a4a716c..293f746 100644 --- a/www/js/newrelic.js +++ b/www/js/newrelic.js @@ -288,7 +288,7 @@ analyticsEventEnabled: function (enabled, cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "analyticsEventEnabled", [enabled]); }, - + /** * Enable or disable reporting sucessful HTTP request to the MobileRequest event type. * @param {boolean} enabled Boolean value for enable successful HTTP requests. @@ -296,7 +296,7 @@ networkRequestEnabled: function (enabled, cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkRequestEnabled", [enabled]); }, - + /** * Enable or disable reporting network and HTTP request errors to the MobileRequestError event type. * @param {boolean} enabled Boolean value for enabling network request errors. @@ -304,15 +304,15 @@ networkErrorRequestEnabled: function (enabled, cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkErrorRequestEnabled", [enabled]); }, - + /** * Enable or disable capture of HTTP response bodies for HTTP error traces, and MobileRequestError events. - * @param {boolean} enabled Boolean value for enabling HTTP response bodies. + * @param {boolean} enabled Boolean value for enabling HTTP response bodies. */ httpRequestBodyCaptureEnabled: function (enabled, cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "httpRequestBodyCaptureEnabled", [enabled]); }, - + /** * Shut down the agent within the current application lifecycle during runtime. * Once the agent has shut down, it cannot be restarted within the current application lifecycle. @@ -320,27 +320,27 @@ shutdown: function (cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "shutdown"); }, - + addHTTPHeadersTrackingFor: function (headers,cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "addHTTPHeadersTrackingFor",[headers]); }, - + getHTTPHeadersTrackingFor: function (cb, fail) { - + return new Promise(function (cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "getHTTPHeadersTrackingFor"); }); }, - + generateDistributedTracingHeaders: function (cb, fail) { - + return new Promise(function (cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "generateDistributedTracingHeaders"); }); }, - + } - + networkRequest = {}; var originalXhrOpen = XMLHttpRequest.prototype.open; var originalXHRSend = XMLHttpRequest.prototype.send; @@ -348,15 +348,15 @@ window.XMLHttpRequest.prototype.open = function (method, url) { // Keep track of the method and url // start time is tracked by the `send` method - + // eslint-disable-next-line prefer-rest-params - + networkRequest.url = url; networkRequest.method = method; networkRequest.bytesSent = 0; networkRequest.startTime = Date.now(); return originalXhrOpen.apply(this, arguments) - + } @@ -401,7 +401,7 @@ networkRequest.body = ""; } - if(isValidURL(networkRequest.url)) { + if(isValidURL(networkRequest.url)) { NewRelic.noticeHttpTransaction(networkRequest.url, networkRequest.method, networkRequest.status, networkRequest.startTime, networkRequest.endTime, networkRequest.bytesSent, networkRequest.bytesreceived, networkRequest.body,networkRequest.params); } } @@ -480,10 +480,7 @@ } }); } else { - if(options === undefined) { - options = {}; - } - options['headers'] = {}; + options = {headers:{}}; options.headers['newrelic'] = headers['newrelic']; options.headers['traceparent'] = headers['traceparent']; options.headers['tracestate'] = headers['tracestate']; @@ -518,8 +515,8 @@ function handleFetchSuccess(response, method, url, startTime,headers,params) { response.text().then((v)=>{ - - if(isValidURL(url)) { + + if(isValidURL(url)) { NewRelic.noticeHttpTransaction( url, method, @@ -533,7 +530,7 @@ headers ); } - + }); } @@ -545,7 +542,7 @@ return false; } } - + const defaultLog = window.console.log; const defaultWarn = window.console.warn; const defaultError = window.console.error; @@ -681,5 +678,4 @@ }; module.exports = NewRelic; - - \ No newline at end of file + From 0eee2d3d8174e0df845a86d4a72ee37028e6cad7 Mon Sep 17 00:00:00 2001 From: ndesai-newrelic <89222514+ndesai-newrelic@users.noreply.github.com> Date: Tue, 5 Mar 2024 10:30:22 -0600 Subject: [PATCH 14/15] Release 6.2.6 (#83) * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * Update iOS agent to 7.4.6 (#73) * Update iOS Version to 7.4.6 * Release 6.2.3 --------- Co-authored-by: ndesai-newrelic Co-authored-by: ndesai-newrelic <89222514+ndesai-newrelic@users.noreply.github.com> * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * resolve merge conflicts with master * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * Add optional attributes for recordError (#69) * feat: add optional attributes parameter for javascript code * feat: handle optional attributes for record error in native code * test: add unit tests for optional attributes parameter in record error * feat: add boolean type for value in optional attributes for record error * test: modify test for record error to test boolean and number values in optional attributes * feat: update README documentation for record error to include optional attributes * resolve merge conflicts with master * merge with master * feature: added offline storage functionality for cordova --------- Co-authored-by: mchavez-newrelic <132291725+mchavez-newrelic@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: ndesai-newrelic --- CHANGELOG.md | 9 +++- README.md | 8 ++++ plugin.xml | 9 ++-- src/android/NewRelicCordovaPlugin.java | 8 ++++ src/ios/NewRelicCordovaPlugin.h | 2 + src/ios/NewRelicCordovaPlugin.m | 9 ++++ www/js/newrelic.js | 65 +++++++++++++++----------- 7 files changed, 78 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 785d389..a23afc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,14 @@ # 6.2.6 ### New in this release -* Fixed a bug in the fetch instrumentation where customer options were inadvertently removed when no headers were specified. Now, options will be preserved even when headers are absent. -* Addressed an issue that resulted in app crashes when an invalid URL was encountered in the capacitor plugin. To mitigate this, a valid URL checker has been implemented to ensure that mobilerequest events are created only with valid URLs. +In this release, we are introducing several new features and updates: +* Added Offline Harvesting Feature: This new feature enables the preservation of harvest data that would otherwise be lost when the application lacks an internet connection. The stored harvests will be sent once the internet connection is re-established and the next harvest upload is successful. +* Introduced setMaxOfflineStorageSize API: This new API allows the user to determine the maximum volume of data that can be stored locally. This aids in better management and control of local data storage. +* Updated native iOS Agent: We've upgraded the native iOS agent to version 7.4.9, which includes performance improvements and bug fixes. +* Updated native Android Agent: We've also upgraded the native Android agent to version 7.3.0 bringing benefits like improved stability and enhanced features. + +These enhancements help to improve overall user experience and application performance. # 6.2.5 diff --git a/README.md b/README.md index 29e76e0..f0b1188 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ Currently, the plugin supports the following agent configuration options: * Possible values are `true` and `false`. Defaults to `false`. * `CONSOLE_LOGS_ENABLED`: Enable or disable reporting javascript console logs as custom events. * Possible values are `true` and `false`. Defaults to `false`. +* `OFFLINE_STORAGE_ENABLED`: Enable or disable offline data storage when no internet connection is available. . + * Possible values are `true` and `false`. Defaults to `true`. # Updating the plugin Update the New Relic Cordova plugin to the latest released version easily via the following command: ``` @@ -211,6 +213,12 @@ Our plugin uses the same APIs as our native agents. See the examples below for u NewRelic.setMaxEventPoolSize(2000); ``` +### [setMaxOfflineStorageSize](https://docs.newrelic.com/docs/mobile-monitoring/new-relic-mobile/mobile-sdk/set-max-offline-storage)(megaBytes: number): void; +> Sets the maximum size of total data that can be stored for offline storage.By default, mobile monitoring can collect a maximum of 100 megaBytes of offline storage. When a data payload fails to send because the device doesn't have an internet connection, it can be stored in the file system until an internet connection has been made. After a typical harvest payload has been successfully sent, all offline data is sent to New Relic and cleared from storage. +```js + NewRelic.setMaxOfflineStorageSize(200); +``` + ### The following methods allow you to set some agent configurations *after* the agent has started: By default, these configurations are already set to true on agent start. diff --git a/plugin.xml b/plugin.xml index a7561ca..1543c74 100644 --- a/plugin.xml +++ b/plugin.xml @@ -18,7 +18,7 @@ - + @@ -29,6 +29,7 @@ + @@ -53,6 +54,7 @@ + @@ -71,7 +73,7 @@ - + @@ -81,7 +83,7 @@ - + @@ -109,6 +111,7 @@ + diff --git a/src/android/NewRelicCordovaPlugin.java b/src/android/NewRelicCordovaPlugin.java index e7ae6ec..b8c17ef 100644 --- a/src/android/NewRelicCordovaPlugin.java +++ b/src/android/NewRelicCordovaPlugin.java @@ -76,6 +76,9 @@ public void initialize(CordovaInterface cordova, CordovaWebView webView) { } if (preferences.getString("default_interactions_enabled", "true").equalsIgnoreCase("false")) { NewRelic.disableFeature(FeatureFlag.DefaultInteractions); + } + if (preferences.getString("offline_storage_enabled", "true").equalsIgnoreCase("true")) { + NewRelic.enableFeature(FeatureFlag.OfflineStorage); } if (preferences.getString("fedramp_enabled", "false").equalsIgnoreCase("true")) { NewRelic.enableFeature(FeatureFlag.FedRampEnabled); @@ -403,6 +406,11 @@ public void run() { NewRelic.setMaxEventBufferTime(maxEventBufferTimeInSeconds); break; } + case "setMaxOfflineStorageSize": { + final int megabytes = args.getInt(0); + NewRelic.setMaxOfflineStorageSize(megabytes); + break; + } case "setMaxEventPoolSize": { final int maxPoolSize = args.getInt(0); NewRelic.setMaxEventPoolSize(maxPoolSize); diff --git a/src/ios/NewRelicCordovaPlugin.h b/src/ios/NewRelicCordovaPlugin.h index 506c509..aaaf8f8 100644 --- a/src/ios/NewRelicCordovaPlugin.h +++ b/src/ios/NewRelicCordovaPlugin.h @@ -49,6 +49,8 @@ - (void)setMaxEventPoolSize:(CDVInvokedUrlCommand *)command; +- (void)setMaxOfflineStorageSize:(CDVInvokedUrlCommand *)command; + - (void)analyticsEventEnabled:(CDVInvokedUrlCommand *) command; - (void)networkRequestEnabled:(CDVInvokedUrlCommand *) command; diff --git a/src/ios/NewRelicCordovaPlugin.m b/src/ios/NewRelicCordovaPlugin.m index 61614c1..95561df 100644 --- a/src/ios/NewRelicCordovaPlugin.m +++ b/src/ios/NewRelicCordovaPlugin.m @@ -55,6 +55,9 @@ - (void)pluginInitialize if (![self shouldDisableFeature:config[@"fedramp_enabled"]]) { [NewRelic enableFeatures:NRFeatureFlag_FedRampEnabled]; } + if (![self shouldDisableFeature:config[@"offline_storage_enabled"]]) { + [NewRelic enableFeatures:NRFeatureFlag_OfflineStorage]; + } // Set log level depending on loggingEnabled and logLevel NRLogLevels logLevel = NRLogLevelWarning; @@ -356,6 +359,12 @@ - (void)setMaxEventPoolSize:(CDVInvokedUrlCommand *)command { [NewRelic setMaxEventPoolSize:uint_maxPoolSize]; } +- (void)setMaxOfflineStorageSize:(CDVInvokedUrlCommand *)command { + NSNumber* megaBytes = [command.arguments objectAtIndex:0]; + unsigned int uint_megaBytes = megaBytes.unsignedIntValue; + [NewRelic setMaxOfflineStorageSize:uint_megaBytes]; +} + - (void)analyticsEventEnabled:(CDVInvokedUrlCommand *)command { // This should only be an android method call, so we do nothing here. return; diff --git a/www/js/newrelic.js b/www/js/newrelic.js index 293f746..1f08782 100644 --- a/www/js/newrelic.js +++ b/www/js/newrelic.js @@ -280,6 +280,14 @@ cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxEventPoolSize", [maxPoolSize]); }, + /** + * Sets the maximum size of total data that can be stored for offline storage.. + * @param {number} maxPoolSize The Maximum size in megaBytes that can be stored in the file system. + */ + setMaxOfflineStorageSize: function (megaBytes, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "setMaxOfflineStorageSize", [megaBytes]); + }, + /** * FOR ANDROID ONLY. * Enable or disable collection of event data. @@ -288,7 +296,7 @@ analyticsEventEnabled: function (enabled, cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "analyticsEventEnabled", [enabled]); }, - + /** * Enable or disable reporting sucessful HTTP request to the MobileRequest event type. * @param {boolean} enabled Boolean value for enable successful HTTP requests. @@ -296,7 +304,7 @@ networkRequestEnabled: function (enabled, cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkRequestEnabled", [enabled]); }, - + /** * Enable or disable reporting network and HTTP request errors to the MobileRequestError event type. * @param {boolean} enabled Boolean value for enabling network request errors. @@ -304,15 +312,15 @@ networkErrorRequestEnabled: function (enabled, cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "networkErrorRequestEnabled", [enabled]); }, - + /** * Enable or disable capture of HTTP response bodies for HTTP error traces, and MobileRequestError events. - * @param {boolean} enabled Boolean value for enabling HTTP response bodies. + * @param {boolean} enabled Boolean value for enabling HTTP response bodies. */ httpRequestBodyCaptureEnabled: function (enabled, cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "httpRequestBodyCaptureEnabled", [enabled]); }, - + /** * Shut down the agent within the current application lifecycle during runtime. * Once the agent has shut down, it cannot be restarted within the current application lifecycle. @@ -320,27 +328,27 @@ shutdown: function (cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "shutdown"); }, - + addHTTPHeadersTrackingFor: function (headers,cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "addHTTPHeadersTrackingFor",[headers]); }, - + getHTTPHeadersTrackingFor: function (cb, fail) { - + return new Promise(function (cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "getHTTPHeadersTrackingFor"); }); }, - + generateDistributedTracingHeaders: function (cb, fail) { - + return new Promise(function (cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "generateDistributedTracingHeaders"); }); }, - + } - + networkRequest = {}; var originalXhrOpen = XMLHttpRequest.prototype.open; var originalXHRSend = XMLHttpRequest.prototype.send; @@ -348,15 +356,15 @@ window.XMLHttpRequest.prototype.open = function (method, url) { // Keep track of the method and url // start time is tracked by the `send` method - + // eslint-disable-next-line prefer-rest-params - + networkRequest.url = url; networkRequest.method = method; networkRequest.bytesSent = 0; networkRequest.startTime = Date.now(); return originalXhrOpen.apply(this, arguments) - + } @@ -401,7 +409,7 @@ networkRequest.body = ""; } - if(isValidURL(networkRequest.url)) { + if(isValidURL(networkRequest.url)) { NewRelic.noticeHttpTransaction(networkRequest.url, networkRequest.method, networkRequest.status, networkRequest.startTime, networkRequest.endTime, networkRequest.bytesSent, networkRequest.bytesreceived, networkRequest.body,networkRequest.params); } } @@ -480,21 +488,24 @@ } }); } else { - options = {headers:{}}; + if(options === undefined) { + options = {}; + } + options['headers'] = {}; options.headers['newrelic'] = headers['newrelic']; options.headers['traceparent'] = headers['traceparent']; options.headers['tracestate'] = headers['tracestate']; _arguments[1] = options; } - if(options && 'body' in options) { - networkRequest.bytesSent = options.body.length; + if (options && 'body' in options && options.body !== undefined) { + networkRequest.bytesSent = options.body.length; } else { - networkRequest.bytesSent = 0; + networkRequest.bytesSent = 0; } - - if (networkRequest.method === undefined || networkRequest.method === "" ) { - networkRequest.method = 'GET'; + + if (networkRequest.method === undefined || networkRequest.method === "") { + networkRequest.method = 'GET'; } return new Promise(function (resolve, reject) { // pass through to native fetch @@ -515,8 +526,8 @@ function handleFetchSuccess(response, method, url, startTime,headers,params) { response.text().then((v)=>{ - - if(isValidURL(url)) { + + if(isValidURL(url)) { NewRelic.noticeHttpTransaction( url, method, @@ -530,7 +541,7 @@ headers ); } - + }); } @@ -542,7 +553,7 @@ return false; } } - + const defaultLog = window.console.log; const defaultWarn = window.console.warn; const defaultError = window.console.error; From ad3780f18c5d0386695d5421b14436e0613646af Mon Sep 17 00:00:00 2001 From: ndesai-newrelic <89222514+ndesai-newrelic@users.noreply.github.com> Date: Tue, 5 Mar 2024 16:24:04 -0600 Subject: [PATCH 15/15] release 6.2.7 (#84) --- CHANGELOG.md | 11 ++++++++++- package.json | 2 +- plugin.xml | 4 ++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a23afc8..6a5c897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog -# 6.2.6 + +# 6.2.7 ### New in this release In this release, we are introducing several new features and updates: @@ -9,9 +10,17 @@ In this release, we are introducing several new features and updates: * Introduced setMaxOfflineStorageSize API: This new API allows the user to determine the maximum volume of data that can be stored locally. This aids in better management and control of local data storage. * Updated native iOS Agent: We've upgraded the native iOS agent to version 7.4.9, which includes performance improvements and bug fixes. * Updated native Android Agent: We've also upgraded the native Android agent to version 7.3.0 bringing benefits like improved stability and enhanced features. +* Resolved an issue in the fetch instrumentation where the absence of a body led to failure in recording network requests by the agent. These enhancements help to improve overall user experience and application performance. +# 6.2.6 + +### New in this release +* Fixed a bug in the fetch instrumentation where customer options were inadvertently removed when no headers were specified. Now, options will be preserved even when headers are absent. +* Addressed an issue that resulted in app crashes when an invalid URL was encountered in the capacitor plugin. To mitigate this, a valid URL checker has been implemented to ensure that mobilerequest events are created only with valid URLs. + + # 6.2.5 ### New in this release diff --git a/package.json b/package.json index 2e2783c..c1d17a1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "newrelic-cordova-plugin", - "version": "6.2.6", + "version": "6.2.7", "description": "New Relic Cordova Plugin for iOS and Android", "repo": "https://github.com/newrelic/newrelic-cordova-plugin/", "scripts": { diff --git a/plugin.xml b/plugin.xml index 1543c74..38fdbe2 100644 --- a/plugin.xml +++ b/plugin.xml @@ -6,7 +6,7 @@ + id="newrelic-cordova-plugin" version="6.2.7"> NewRelic New Relic Cordova Plugin for iOS and Android New Relic @@ -18,7 +18,7 @@ - +