Skip to content

Commit

Permalink
Merge pull request #68 from newrelic/release_6.2.1
Browse files Browse the repository at this point in the history
Release 6.2.1
  • Loading branch information
kennyt276 authored Jun 9, 2023
2 parents 6789ba7 + 049fd9c commit 3cb2cfe
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 21 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

# 6.2.1

### New in this release
* Upgrade native iOS agent to v7.4.5
* Added agent configuration options when adding the plugin to your project.

### Fixed in this release
* Fixed an issue where certain JS errors were improperly parsed on iOS.

# 6.2.0

### New in this release
Expand Down
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,43 @@ If you don't have a New Relic account, [create a free trial](https://newrelic.co

Finally, copy the application tokens from your New Relic applications page, and have them ready for the next step. You only need to copy the application tokens of the platforms you are building on.

### Adding the plugin
## Adding the plugin
Change to your Cordova project directory and add the plugin to your project using the Cordova command line tool. The `--variable` argument is used to pass application tokens to the plugin.
```
# Install from github repository
cordova plugin add https://github.com/newrelic/newrelic-cordova-plugin.git --variable IOS_APP_TOKEN="{ios-app-token}" --variable ANDROID_APP_TOKEN="{android-app-token}"
```

### Agent Configuration Options
***These options are only available on Cordova plugin v6.2.1 and above.***

The `--variable` argument can also be used to add optional configuration options on agent start to the plugin.
```
# Disable Crash Reporting
cordova plugin add https://github.com/newrelic/newrelic-cordova-plugin.git --variable IOS_APP_TOKEN="{ios-app-token}" --variable ANDROID_APP_TOKEN="{android-app-token}" --variable CRASH_REPORTING_ENABLED="false"
```

Currently, the plugin supports the following agent configuration options:
* `CRASH_REPORTING_ENABLED`: Enable or disable crash reporting.
* Possible values are `true` and `false`. Defaults to `true`.
* `DISTRIBUTED_TRACING_ENABLED`: Enable or disable the adding of distributed tracing headers to network requests.
* Possible values are `true` and `false`. Defaults to `true`.
* `INTERACTION_TRACING_ENABLED`: Enable or disable interaction tracing. Trace instrumentation still occurs, but no traces are harvested. This will disable default and custom interactions.
* Possible values are `true` and `false`. Defaults to `true`.
* `DEFAULT_INTERACTIONS_ENABLED`: Enable or disable default interactions. Trace instrumentation still occurs, but no traces are harvested. This will enable or disable default interactions only while custom interactions remain enabled.
* Possible values are `true` and `false`. Defaults to `true`.
* `LOGGING_ENABLED`: Enable or disable agent logging.
* Possible values are `true` and `false`. Defaults to `true`.
* `LOG_LEVEL`: Specifies the log level.
* Possible values are `ERROR` (least verbose), `WARNING` `INFO`, `VERBOSE`, `DEBUG`, `AUDIT` (most verbose).
* Defaults to `INFO` on Android and `WARNING` on iOS.
* `WEB_VIEW_INSTRUMENTATION` (iOS ONLY): Enable (default) or disable automatic WKWebView instrumentation.
* Possible values are `true` and `false`. Defaults to `true`.
* `COLLECTOR_ADDRESS`: Specifies the URI authority component of the harvest data upload endpoint.
* `CRASH_COLLECTOR_ADDRESS`: Specifies the authority component of the crash data upload URI.
* `FEDRAMP_ENABLED`: Enable or disable reporting data using different endpoints for US government clients.
* Possible values are `true` and `false`. Defaults to `false`.

# Updating the plugin
Update the New Relic Cordova plugin to the latest released version easily via the following command:
```
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "newrelic-cordova-plugin",
"version": "6.1.0",
"version": "6.2.1",
"description": "New Relic Cordova Plugin for iOS and Android",
"repo": "https://github.com/newrelic/newrelic-cordova-plugin/",
"scripts": {
Expand Down
37 changes: 33 additions & 4 deletions plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<?xml version="1.0" encoding="UTF-8"?>

<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
id="newrelic-cordova-plugin" version="6.2.0">
id="newrelic-cordova-plugin" version="6.2.1">
<name>NewRelic</name>
<description>New Relic Cordova Plugin for iOS and Android</description>
<author>New Relic</author>
Expand All @@ -18,8 +18,17 @@
<engine name="cordova-android" version=">=5.0.0" />
</engines>

<preference name="PLUGIN_VERSION" default="6.2.0" />

<preference name="PLUGIN_VERSION" default="6.2.1" />
<preference name="CRASH_REPORTING_ENABLED" default="true" />
<preference name="DISTRIBUTED_TRACING_ENABLED" default="true" />
<preference name="INTERACTION_TRACING_ENABLED" default="true" />
<preference name="DEFAULT_INTERACTIONS_ENABLED" default="true" />
<preference name="LOGGING_ENABLED" default="true" />
<preference name="LOG_LEVEL" default="default" />
<preference name="WEB_VIEW_INSTRUMENTATION" default="true" />
<preference name="COLLECTOR_ADDRESS" default="x" />
<preference name="CRASH_COLLECTOR_ADDRESS" default="x" />
<preference name="FEDRAMP_ENABLED" default="false" />

<platform name="ios">
<preference name="IOS_APP_TOKEN" default="x" />
Expand All @@ -32,6 +41,16 @@
<feature name="NewRelicCordovaPlugin">
<preference name="IOS_APP_TOKEN" value="$IOS_APP_TOKEN" />
<preference name="PLUGIN_VERSION" value="$PLUGIN_VERSION" />
<preference name="CRASH_REPORTING_ENABLED" value="$CRASH_REPORTING_ENABLED" />
<preference name="DISTRIBUTED_TRACING_ENABLED" value="$DISTRIBUTED_TRACING_ENABLED" />
<preference name="INTERACTION_TRACING_ENABLED" value="$INTERACTION_TRACING_ENABLED" />
<preference name="DEFAULT_INTERACTIONS_ENABLED" value="$DEFAULT_INTERACTIONS_ENABLED" />
<preference name="LOGGING_ENABLED" value="$LOGGING_ENABLED" />
<preference name="LOG_LEVEL" value="$LOG_LEVEL" />
<preference name="WEB_VIEW_INSTRUMENTATION" value="$WEB_VIEW_INSTRUMENTATION" />
<preference name="COLLECTOR_ADDRESS" value="$COLLECTOR_ADDRESS" />
<preference name="CRASH_COLLECTOR_ADDRESS" value="$CRASH_COLLECTOR_ADDRESS" />
<preference name="FEDRAMP_ENABLED" value="$FEDRAMP_ENABLED" />
<param name="ios-package" value="NewRelicCordovaPlugin" onload="true" />
</feature>
</config-file>
Expand All @@ -49,7 +68,7 @@
<source url="https://cdn.cocoapods.org/" />
</config>
<pods use-frameworks="true">
<pod name="NewRelicAgent" spec="7.4.4" />
<pod name="NewRelicAgent" spec="7.4.5" />
</pods>
</podspec>

Expand Down Expand Up @@ -77,6 +96,16 @@
</feature>
<preference name="ANDROID_APP_TOKEN" value="$ANDROID_APP_TOKEN" />
<preference name="PLUGIN_VERSION" value="$PLUGIN_VERSION" />
<preference name="CRASH_REPORTING_ENABLED" value="$CRASH_REPORTING_ENABLED" />
<preference name="DISTRIBUTED_TRACING_ENABLED" value="$DISTRIBUTED_TRACING_ENABLED" />
<preference name="INTERACTION_TRACING_ENABLED" value="$INTERACTION_TRACING_ENABLED" />
<preference name="DEFAULT_INTERACTIONS_ENABLED" value="$DEFAULT_INTERACTIONS_ENABLED" />
<preference name="LOGGING_ENABLED" value="$LOGGING_ENABLED" />
<preference name="LOG_LEVEL" value="$LOG_LEVEL" />
<preference name="WEB_VIEW_INSTRUMENTATION" value="$WEB_VIEW_INSTRUMENTATION" />
<preference name="COLLECTOR_ADDRESS" value="$COLLECTOR_ADDRESS" />
<preference name="CRASH_COLLECTOR_ADDRESS" value="$CRASH_COLLECTOR_ADDRESS" />
<preference name="FEDRAMP_ENABLED" value="$FEDRAMP_ENABLED" />
</config-file>

<source-file src="src/android/NewRelicCordovaPlugin.java"
Expand Down
65 changes: 59 additions & 6 deletions src/android/NewRelicCordovaPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.newrelic.agent.android.distributedtracing.TraceContext;
import com.newrelic.agent.android.distributedtracing.TraceHeader;
import com.newrelic.agent.android.harvest.DeviceInformation;
import com.newrelic.agent.android.logging.AgentLog;
import com.newrelic.agent.android.stats.StatsEngine;
import com.newrelic.agent.android.metric.MetricUnit;
import com.newrelic.agent.android.util.NetworkFailure;
Expand Down Expand Up @@ -52,24 +53,76 @@ public void initialize(CordovaInterface cordova, CordovaWebView webView) {

String appToken = preferences.getString("ANDROID_APP_TOKEN", null);

if (appToken == null || appToken.isEmpty() || "x".equals(appToken)) {
if (isEmptyConfigParameter(appToken)) {
Log.e(TAG, "Failed to load application token! The Android agent is not configured for Cordova.");

} else {

final String pluginVersion = preferences.getString("PLUGIN_VERSION", "undefined");
final DeviceInformation devInfo = Agent.getDeviceInformation();

NewRelic.withApplicationToken(appToken)
.withApplicationFramework(ApplicationFramework.Cordova, pluginVersion)
.withLoggingEnabled(true)
.start(this.cordova.getActivity().getApplication());
if (preferences.getString("CRASH_REPORTING_ENABLED", "true").equalsIgnoreCase("false")) {
NewRelic.disableFeature(FeatureFlag.CrashReporting);
}
if (preferences.getString("DISTRIBUTED_TRACING_ENABLED", "true").equalsIgnoreCase("false")) {
NewRelic.disableFeature(FeatureFlag.DistributedTracing);
}
if (preferences.getString("INTERACTION_TRACING_ENABLED", "true").equalsIgnoreCase("false")) {
NewRelic.disableFeature(FeatureFlag.InteractionTracing);
}
if (preferences.getString("DEFAULT_INTERACTIONS_ENABLED", "true").equalsIgnoreCase("false")) {
NewRelic.disableFeature(FeatureFlag.DefaultInteractions);
}
if (preferences.getString("FEDRAMP_ENABLED", "false").equalsIgnoreCase("true")) {
NewRelic.enableFeature(FeatureFlag.FedRampEnabled);
}

Map<String, Integer> strToLogLevel = new HashMap<>();
strToLogLevel.put("ERROR", AgentLog.ERROR);
strToLogLevel.put("WARNING", AgentLog.WARN);
strToLogLevel.put("INFO", AgentLog.INFO);
strToLogLevel.put("VERBOSE", AgentLog.VERBOSE);
strToLogLevel.put("AUDIT", AgentLog.AUDIT);

int logLevel = AgentLog.INFO;
String configLogLevel = preferences.getString("LOG_LEVEL", "INFO").toUpperCase();
if (strToLogLevel.containsKey(configLogLevel)) {
logLevel = strToLogLevel.get(configLogLevel);
}

String collectorAddress = preferences.getString("COLLECTOR_ADDRESS", null);
String crashCollectorAddress = preferences.getString("CRASH_COLLECTOR_ADDRESS", null);

NewRelic newRelic = NewRelic.withApplicationToken(appToken)
.withApplicationFramework(ApplicationFramework.Cordova, pluginVersion)
.withLoggingEnabled(preferences.getString("LOGGING_ENABLED", "true").toLowerCase().equals("true"))
.withLogLevel(logLevel);

if (isEmptyConfigParameter(collectorAddress) && isEmptyConfigParameter(crashCollectorAddress)) {
newRelic.start(this.cordova.getActivity().getApplication());
} else {
// Set missing collector addresses (if any)
if (collectorAddress == null) {
collectorAddress = "mobile-collector.newrelic.com";
}
if (crashCollectorAddress == null) {
crashCollectorAddress = "mobile-crash.newrelic.com";
}
newRelic.usingCollectorAddress(collectorAddress);
newRelic.usingCrashCollectorAddress(crashCollectorAddress);
newRelic.start(this.cordova.getActivity().getApplication());
}

newRelic.start(this.cordova.getActivity().getApplication());

NewRelic.setAttribute(AnalyticsAttribute.APPLICATION_PLATFORM_VERSION_ATTRIBUTE, pluginVersion);
}

}

public boolean isEmptyConfigParameter(String parameter) {
return parameter == null || parameter.isEmpty() || parameter.equals("x");
}

public StackTraceElement[] parseStackTrace(String stack) {
String[] lines = stack.split("\n");
ArrayList<StackTraceElement> stackTraceList = new ArrayList<>();
Expand Down
86 changes: 78 additions & 8 deletions src/ios/NewRelicCordovaPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ @implementation NewRelicCordovaPlugin {
- (void)pluginInitialize
{
NSString* applicationToken = [self.commandDelegate.settings objectForKey:@"ios_app_token"];
NSString* platformVersion = [self.commandDelegate.settings objectForKey:@"plugin_version"];

NSDictionary* config = self.commandDelegate.settings;

jscRegex = [NSRegularExpression regularExpressionWithPattern:@"^\\s*(?:([^@]*)(?:\\((.*?)\\))?@)?(\\S.*?):(\\d+)(?::(\\d+))?\\s*$"
options:NSRegularExpressionCaseInsensitive
Expand All @@ -31,16 +32,82 @@ - (void)pluginInitialize
options:NSRegularExpressionCaseInsensitive
error:nil];

if (applicationToken == nil || ([applicationToken isEqualToString:@""] || [applicationToken isEqualToString:@"x"])) {
if ([self isEmptyConfigParameter:applicationToken]) {
NRLOG_ERROR(@"Failed to load application token! The iOS agent is not configured for Cordova.");

} else {

if ([self shouldDisableFeature:config[@"crash_reporting_enabled"]]) {
[NewRelic disableFeatures:NRFeatureFlag_CrashReporting];
}
if ([self shouldDisableFeature:config[@"distributed_tracing_enabled"]]) {
[NewRelic disableFeatures:NRFeatureFlag_DistributedTracing];
}
if ([self shouldDisableFeature:config[@"interaction_tracing_enabled"]]) {
[NewRelic disableFeatures:NRFeatureFlag_InteractionTracing];
}
if ([self shouldDisableFeature:config[@"default_interactions_enabled"]]) {
[NewRelic disableFeatures:NRFeatureFlag_DefaultInteractions];
}
if ([self shouldDisableFeature:config[@"web_view_instrumentation"]]) {
[NewRelic disableFeatures:NRFeatureFlag_WebViewInstrumentation];
}
if (![self shouldDisableFeature:config[@"fedramp_enabled"]]) {
[NewRelic enableFeatures:NRFeatureFlag_FedRampEnabled];
}

// Set log level depending on loggingEnabled and logLevel
NRLogLevels logLevel = NRLogLevelWarning;
NSDictionary *logDict = @{
@"ERROR": [NSNumber numberWithInt:NRLogLevelError],
@"WARNING": [NSNumber numberWithInt:NRLogLevelWarning],
@"INFO": [NSNumber numberWithInt:NRLogLevelInfo],
@"VERBOSE": [NSNumber numberWithInt:NRLogLevelVerbose],
@"AUDIT": [NSNumber numberWithInt:NRLogLevelAudit],
};
if ([logDict objectForKey:[config[@"log_level"] uppercaseString]]) {
NSString* configLogLevel = [config[@"log_level"] uppercaseString];
NSNumber* newLogLevel = [logDict valueForKey:configLogLevel];
logLevel = [newLogLevel intValue];
}
if ([self shouldDisableFeature:config[@"logging_enabled"]]) {
logLevel = NRLogLevelNone;
}
[NRLogger setLogLevels:logLevel];


NSString* collectorAddress = config[@"collector_address"];
NSString* crashCollectorAddress = config[@"crash_collector_address"];

[NewRelic setPlatform:NRMAPlatform_Cordova];
[NewRelic setPlatformVersion:platformVersion];
[NewRelic startWithApplicationToken:applicationToken];
[NewRelic setPlatformVersion:config[@"plugin_version"]];

if ([self isEmptyConfigParameter:collectorAddress] && [self isEmptyConfigParameter:crashCollectorAddress]) {
[NewRelic startWithApplicationToken:applicationToken];
} else {
// Set to default collector endpoints if only one of two addresses was set
if ([self isEmptyConfigParameter:collectorAddress]) {
collectorAddress = @"mobile-collector.newrelic.com";
}
if ([self isEmptyConfigParameter:crashCollectorAddress]) {
crashCollectorAddress = @"mobile-crash.newrelic.com";
}

[NewRelic startWithApplicationToken:applicationToken
andCollectorAddress:collectorAddress
andCrashCollectorAddress:crashCollectorAddress];
}
}
}

- (BOOL)isEmptyConfigParameter:(NSString *)param {
return param == nil || ([param isEqualToString:@""] || [param isEqualToString:@"x"]);
}

- (BOOL)shouldDisableFeature:(NSString *)flag {
return [[flag lowercaseString] isEqualToString:@"false"];
}

- (void)recordBreadCrumb:(CDVInvokedUrlCommand *)command {
NSString* name = [command.arguments objectAtIndex:0];
NSDictionary *attributes = [command.arguments objectAtIndex:1];
Expand Down Expand Up @@ -111,10 +178,13 @@ - (NSMutableArray*)parseStackTrace:(NSString*)stackString {
}

NSMutableDictionary* stackTraceElement = [NSMutableDictionary new];
stackTraceElement[@"method"] = [line substringWithRange:[result[0] rangeAtIndex:1]];
stackTraceElement[@"file"] = [line substringWithRange:[result[0] rangeAtIndex:3]];
NSNumber* lineNum = @([[line substringWithRange:[result[0] rangeAtIndex:4]] intValue]);
stackTraceElement[@"line"] = lineNum;
NSRange methodRange = [result[0] rangeAtIndex:1];
NSRange fileRange = [result[0] rangeAtIndex:3];
NSRange lineNumRange = [result[0] rangeAtIndex:4];

stackTraceElement[@"method"] = methodRange.length == 0 ? @" " : [line substringWithRange:methodRange];
stackTraceElement[@"file"] = fileRange.length == 0 ? @" " : [line substringWithRange:fileRange];
stackTraceElement[@"line"] = lineNumRange.length == 0 ? [NSNumber numberWithInt:1] : @([[line substringWithRange:lineNumRange] intValue]);

[stackFramesArr addObject:stackTraceElement];
}
Expand Down
8 changes: 7 additions & 1 deletion tests/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,12 @@ exports.defineAutoTests = () => {
spyOn(cordova, "exec").and.callThrough();
spyOn(window.console, "warn").and.callThrough();

// should parse errors with missing fields
let exampleError = new Error();
exampleError.name = 'fakeErrorName';
exampleError.message = 'fakeMsg';
exampleError.stack = 'fakeStack';
exampleError.stack = 'ionic://com.example.app.poc:8100/plugins/newrelic-cordova-plugin/www/js/missingmethod.js:123:45\nmissingfile@:1:2345\nmissinglinenum@ionic://com.example.app.poc:8100/example.js::\nregularstackline@ionic://com.example.app.poc:8100/example.js:1:23456';
// will crash if unable to execute
window.NewRelic.recordError(exampleError);
window.NewRelic.recordError(new TypeError);
window.NewRelic.recordError(new EvalError);
Expand All @@ -143,6 +145,10 @@ exports.defineAutoTests = () => {
expect(window.NewRelic.recordError).toHaveBeenCalledTimes(10);
});

it('should parse JS error with missing fields', () => {

});

it('should have currentSessionId', () => {
expect(window.NewRelic.currentSessionId() instanceof Promise).toBe(true);
spyOn(window.NewRelic, "currentSessionId").and.callThrough();
Expand Down

0 comments on commit 3cb2cfe

Please sign in to comment.