Skip to content

Commit c5c0898

Browse files
Xml http request distributed tracing (#105)
* NR-362528_DT_FR * release 7.0.5
1 parent 59e1b96 commit c5c0898

6 files changed

+152
-7
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
# 7.0.5
4+
5+
## Improvements
6+
7+
- Implemented Distributed Tracing support for `XMLHttpRequest`.
8+
- Updated the Native Android agent to version 7.6.4.
9+
10+
311
# 7.0.4
412

513
## Improvements

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "newrelic-cordova-plugin",
3-
"version": "7.0.4",
3+
"version": "7.0.5",
44
"description": "New Relic Cordova Plugin for iOS and Android",
55
"repo": "https://github.com/newrelic/newrelic-cordova-plugin/",
66
"scripts": {

plugin.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<?xml version="1.0" encoding="UTF-8"?>
77

88
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
9-
id="newrelic-cordova-plugin" version="7.0.4">
9+
id="newrelic-cordova-plugin" version="7.0.5">
1010
<name>NewRelic</name>
1111
<description>New Relic Cordova Plugin for iOS and Android</description>
1212
<author>New Relic</author>
@@ -89,7 +89,7 @@
8989

9090
<platform name="android">
9191
<preference name="ANDROID_APP_TOKEN" default="x" />
92-
<preference name="ANDROID_AGENT_VER" default="7.6.2" />
92+
<preference name="ANDROID_AGENT_VER" default="7.6.4" />
9393

9494
<config-file target="AndroidManifest.xml" parent="/*">
9595
<uses-permission android:name="android.permission.INTERNET" />

src/android/NewRelicCordovaPlugin.java

+6
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,9 @@ public void run() {
323323
dtHeaders.put(NRTraceConstants.TRACE_ID, traceId);
324324
dtHeaders.put(NRTraceConstants.ID, spanId);
325325
dtHeaders.put(NRTraceConstants.GUID, spanId);
326+
dtHeaders.put(NRTraceConstants.ACCOUNT_ID,accountId);
327+
dtHeaders.put(NRTraceConstants.APPLICATION_ID,applicationId);
328+
dtHeaders.put(NRTraceConstants.TRUST_ACCOUNT_KEY,vendor.substring(0,vendor.indexOf("@")));
326329

327330

328331
callbackContext.success(dtHeaders);
@@ -595,6 +598,9 @@ protected static final class NRTraceConstants {
595598
public static final String TRACE_ID = "trace.id";
596599
public static final String GUID = "guid";
597600
public static final String ID = "id";
601+
public static final String ACCOUNT_ID = "account.id";
602+
public static final String APPLICATION_ID = "application.id";
603+
public static final String TRUST_ACCOUNT_KEY = "trust.account.key";
598604
}
599605

600606
}

src/ios/NewRelicCordovaPlugin.m

+30-2
Original file line numberDiff line numberDiff line change
@@ -463,8 +463,36 @@ - (void)generateDistributedTracingHeaders:(CDVInvokedUrlCommand *)command {
463463

464464
NSDictionary<NSString*,NSString*>* headers = [NewRelic generateDistributedTracingHeaders];
465465

466-
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:headers];
467-
466+
NSMutableDictionary *mutableDictionary = [headers mutableCopy];
467+
468+
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:headers[@"newrelic"] options:0];
469+
470+
NSError *error = nil;
471+
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:decodedData options:0 error:&error];
472+
473+
if (error) {
474+
NSLog(@"Error parsing JSON: %@", error);
475+
} else {
476+
NSLog(@"JSON Object: %@", jsonObject);
477+
// Access individual values from the JSON object
478+
NSDictionary *dDictionary = jsonObject[@"d"];
479+
NSString *acNumber = dDictionary[@"ac"];
480+
NSString *apNumber = dDictionary[@"ap"];
481+
NSString *tkNumber = dDictionary[@"tk"];
482+
483+
484+
485+
[mutableDictionary setObject:acNumber forKey:@"application.id"];
486+
[mutableDictionary setObject:apNumber forKey:@"account.id"];
487+
488+
if(tkNumber != nil) {
489+
[mutableDictionary setObject:tkNumber forKey:@"trust.account.key"];
490+
} else {
491+
[mutableDictionary setObject:acNumber forKey:@"trust.account.key"];
492+
}
493+
}
494+
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:mutableDictionary];
495+
468496
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
469497

470498
}

www/js/newrelic.js

+105-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
*/
55

66
var exec = require("cordova/exec");
7+
8+
var accountId = "";
9+
var applicationId = "";
10+
var trustAccountKey = "";
11+
712

813
var NewRelic = {
914

@@ -501,8 +506,18 @@
501506
networkRequest.method = method;
502507
networkRequest.bytesSent = 0;
503508
networkRequest.startTime = Date.now();
504-
return originalXhrOpen.apply(this, arguments)
505-
509+
try {
510+
return originalXhrOpen.apply(this, arguments)
511+
} catch (e) {
512+
console.error(e);
513+
} finally{
514+
var headers = generateTracePayload();
515+
516+
this.setRequestHeader("newrelic", headers['newrelic']);
517+
this.setRequestHeader("traceparent", headers['traceparent']);
518+
this.setRequestHeader("tracestate", headers['tracestate']);
519+
networkRequest.params = headers;
520+
}
506521
}
507522

508523

@@ -680,6 +695,94 @@
680695
});
681696
}
682697

698+
function generateTracePayload () {
699+
700+
if (!accountId || !applicationId) {
701+
return null
702+
}
703+
704+
var guid = generateSpanId()
705+
var traceId = generateTraceId()
706+
var timestamp = Date.now()
707+
708+
var payload = {
709+
guid,
710+
traceId
711+
}
712+
payload.id = guid;
713+
payload['trace.id'] = payload.traceId;
714+
715+
payload.traceparent = generateTraceContextParentHeader(guid, traceId)
716+
payload.tracestate = generateTraceContextStateHeader(guid, timestamp,
717+
accountId, applicationId, trustAccountKey)
718+
719+
payload.newrelic = generateTraceHeader(guid, traceId, timestamp, accountId,
720+
applicationId, trustAccountKey)
721+
722+
723+
return payload
724+
}
725+
726+
function generateSpanId() {
727+
return generateRandomHexString(16);
728+
}
729+
730+
function generateTraceId() {
731+
return generateRandomHexString(32);
732+
}
733+
734+
function generateRandomHexString(length) {
735+
const chars = '0123456789abcdef';
736+
let result = '';
737+
for (let i = 0; i < length; i++) {
738+
result += chars[Math.floor(Math.random() * chars.length)];
739+
}
740+
return result;
741+
}
742+
743+
function generateTraceContextParentHeader (spanId, traceId) {
744+
return '00-' + traceId + '-' + spanId + '-01'
745+
}
746+
747+
function generateTraceContextStateHeader (spanId, timestamp, accountId, appId, trustKey) {
748+
var version = 0
749+
var transactionId = ''
750+
var parentType = 2
751+
var sampled = ''
752+
var priority = ''
753+
754+
return trustKey + '@nr=' + version + '-' + parentType + '-' + accountId +
755+
'-' + appId + '-' + spanId + '-' + transactionId + '-' + sampled + '-' + priority + '-' + timestamp
756+
}
757+
758+
function generateTraceHeader (spanId, traceId, timestamp, accountId, appId, trustKey) {
759+
760+
var payload = {
761+
v: [0, 2],
762+
d: {
763+
ty: 'Mobile',
764+
ac: accountId,
765+
ap: appId,
766+
id: spanId,
767+
tr: traceId,
768+
ti: timestamp
769+
}
770+
}
771+
if (trustKey && accountId !== trustKey) {
772+
payload.d.tk = trustKey
773+
}
774+
775+
return btoa(JSON.stringify(payload))
776+
}
777+
778+
document.addEventListener('deviceready', function () {
779+
NewRelic.generateDistributedTracingHeaders().then((headers) => {
780+
accountId = headers['account.id'];
781+
applicationId = headers['application.id'];
782+
trustAccountKey = headers['trust.account.key'];
783+
});
784+
});
785+
683786
function isValidURL(url) {
684787
try {
685788
const newUrl = new URL(url);

0 commit comments

Comments
 (0)