newrelic 9.7.5 → 9.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NEWS.md +23 -12
- package/api.js +136 -96
- package/package.json +1 -1
package/NEWS.md
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
|
-
### v9.
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
### v9.8.0 (2023-01-17)
|
|
2
|
+
|
|
3
|
+
* Updated `getBrowserTimingHeader` to allow Browser Agent to be generated even when not in a Transaction by adding `allowTransactionlessInjection` to function options. `allowTransactionlessInjection` is a boolean option, and when set to `true`, will allow injection of the Browser Agent when not in a transaction. This is intended to be used in frameworks that build Static Site Generation(SSG). Note that if you are using this option, you may need to wait until the Node agent has established a connection before calling `getBrowserTimingHeader`. To wait until the agent is connected, you can add the following check to your code:
|
|
4
|
+
```js
|
|
5
|
+
if (!newrelic.agent.collector.isConnected()) {
|
|
6
|
+
await new Promise((resolve) => {
|
|
7
|
+
newrelic.agent.on('connected', resolve)
|
|
8
|
+
})
|
|
9
|
+
}
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
### v9.7.5 (2023-01-03)
|
|
13
|
+
|
|
14
|
+
* Added a check to the code level metrics utility to ensure filePath was set before adding the `code.*` attributes.
|
|
15
|
+
|
|
16
|
+
* Updated to latest version of `@newrelic/test-utilities`
|
|
17
|
+
|
|
18
|
+
* Fixed issue where listing of dependencies and packages from symlinked nested directories created an infinite loop which caused the agent to never connect.
|
|
19
|
+
|
|
20
|
+
### v9.7.4 (2022-12-15)
|
|
21
|
+
|
|
22
|
+
* Fixed system info gathering to prevent unhandled promise rejection when an error occurs reading `/proc` information.
|
|
23
|
+
|
|
13
24
|
### v9.7.3 (2022-12-12)
|
|
14
25
|
|
|
15
26
|
* Added support for Code Level Metrics on API methods: `startSegment`, `startBackgroundTransaction`, and `startWebTransaction`.
|
package/api.js
CHANGED
|
@@ -40,7 +40,7 @@ const RUM_STUB_SHELL_WITH_NONCE_PARAM = `<script type='text/javascript' %s>${RUM
|
|
|
40
40
|
// these messages are used in the _gracefail() method below in getBrowserTimingHeader
|
|
41
41
|
const RUM_ISSUES = [
|
|
42
42
|
'NREUM: no browser monitoring headers generated; disabled',
|
|
43
|
-
'NREUM: transaction
|
|
43
|
+
'NREUM: transaction ignored while generating browser monitoring headers',
|
|
44
44
|
'NREUM: config.browser_monitoring missing, something is probably wrong',
|
|
45
45
|
'NREUM: browser_monitoring headers need a transaction name',
|
|
46
46
|
'NREUM: browser_monitoring requires valid application_id',
|
|
@@ -640,144 +640,180 @@ function _generateRUMHeader(options = {}, metadata, loader) {
|
|
|
640
640
|
}
|
|
641
641
|
|
|
642
642
|
/**
|
|
643
|
-
*
|
|
644
|
-
*
|
|
645
|
-
* in the header, but _after_ any X-UA-COMPATIBLE HTTP-EQUIV meta tags.
|
|
646
|
-
* Otherwise you may hurt IE!
|
|
647
|
-
*
|
|
648
|
-
* By default this method will return a script wrapped by `<script>` tags, but with
|
|
649
|
-
* option `hasToRemoveScriptWrapper` it can send back only the script content
|
|
650
|
-
* without the `<script>` wrapper. Useful for React component based frontend.
|
|
651
|
-
*
|
|
652
|
-
* This method must be called _during_ a transaction, and must be called every
|
|
653
|
-
* time you want to generate the headers.
|
|
643
|
+
* Helper method for determining if we have the minimum required
|
|
644
|
+
* information to generate our Browser Agent script tag
|
|
654
645
|
*
|
|
655
|
-
*
|
|
656
|
-
*
|
|
657
|
-
* @param {
|
|
658
|
-
* @
|
|
659
|
-
* @param {boolean} [options.hasToRemoveScriptWrapper] - Used to import agent script without `<script>` tag wrapper.
|
|
660
|
-
* @returns {string} The script content to be injected in `<head>` or put inside `<script>` tag (depending on options)
|
|
646
|
+
* @param {object} config agent configuration settings
|
|
647
|
+
* @param {Transaction} transaction the active transaction or null
|
|
648
|
+
* @param {boolean} allowTransactionlessInjection whether or not to allow the Browser Agent to be injected when there is no active transaction
|
|
649
|
+
* @returns {{ isValidConfig: boolean, failureIdx?: number, quietMode?: boolean }} object containing validation results
|
|
661
650
|
*/
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
const browserMonitoring = config.browser_monitoring
|
|
671
|
-
|
|
672
|
-
// config.browser_monitoring should always exist, but we don't want the agent
|
|
673
|
-
// to bail here if something goes wrong
|
|
674
|
-
if (!browserMonitoring) {
|
|
675
|
-
return _gracefail(2)
|
|
651
|
+
function validateBrowserMonitoring(config, transaction, allowTransactionlessInjection) {
|
|
652
|
+
/*
|
|
653
|
+
* config.browser_monitoring should always exist, but we don't want the agent
|
|
654
|
+
* to bail here if something goes wrong
|
|
655
|
+
*/
|
|
656
|
+
if (!config.browser_monitoring) {
|
|
657
|
+
return { isValidConfig: false, failureIdx: 2 }
|
|
676
658
|
}
|
|
677
659
|
|
|
678
|
-
/*
|
|
660
|
+
/*
|
|
661
|
+
* Can control header generation with configuration this setting is only
|
|
679
662
|
* available in the newrelic.js config file, it is not ever set by the
|
|
680
663
|
* server.
|
|
681
664
|
*/
|
|
682
|
-
if (!
|
|
665
|
+
if (!config.browser_monitoring.enable) {
|
|
683
666
|
// It has been disabled by the user; no need to warn them about their own
|
|
684
667
|
// settings so fail quietly and gracefully.
|
|
685
|
-
return
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
const trans = this.agent.getTransaction()
|
|
689
|
-
|
|
690
|
-
// bail gracefully outside a transaction
|
|
691
|
-
if (!trans || trans.isIgnored()) {
|
|
692
|
-
return _gracefail(1)
|
|
668
|
+
return { isValidConfig: false, failureIdx: 0, quietMode: true }
|
|
693
669
|
}
|
|
694
670
|
|
|
695
|
-
const name = trans.getFullName()
|
|
696
|
-
|
|
697
|
-
/* If we're in an unnamed transaction, add a friendly warning this is to
|
|
698
|
-
* avoid people going crazy, trying to figure out why browser monitoring is
|
|
699
|
-
* not working when they're missing a transaction name.
|
|
700
|
-
*/
|
|
701
|
-
if (!name) {
|
|
702
|
-
return _gracefail(3)
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
const time = trans.timer.getDurationInMillis()
|
|
706
|
-
|
|
707
671
|
/*
|
|
708
|
-
*
|
|
709
|
-
* the transaction name.
|
|
710
|
-
*/
|
|
711
|
-
const key = config.license_key.substr(0, 13)
|
|
712
|
-
const appid = config.application_id
|
|
713
|
-
|
|
714
|
-
/* This is only going to work if the agent has successfully handshaked with
|
|
672
|
+
* This is only going to work if the agent has successfully handshaked with
|
|
715
673
|
* the collector. If the networks is bad, or there is no license key set in
|
|
716
674
|
* newrelic.js, there will be no application_id set. We bail instead of
|
|
717
675
|
* outputting null/undefined configuration values.
|
|
718
676
|
*/
|
|
719
|
-
if (!
|
|
720
|
-
return
|
|
677
|
+
if (!config.application_id) {
|
|
678
|
+
return { isValidConfig: false, failureIdx: 4 }
|
|
721
679
|
}
|
|
722
680
|
|
|
723
|
-
/*
|
|
681
|
+
/*
|
|
682
|
+
* If there is no browser_key, the server has likely decided to disable
|
|
724
683
|
* browser monitoring.
|
|
725
684
|
*/
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
return _gracefail(5)
|
|
685
|
+
if (!config.browser_monitoring.browser_key) {
|
|
686
|
+
return { isValidConfig: false, failureIdx: 5 }
|
|
729
687
|
}
|
|
730
688
|
|
|
731
|
-
/*
|
|
689
|
+
/*
|
|
690
|
+
* If there is no agent_loader script, there is no point
|
|
732
691
|
* in setting the rum data
|
|
733
692
|
*/
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
return _gracefail(6)
|
|
693
|
+
if (!config.browser_monitoring.js_agent_loader) {
|
|
694
|
+
return { isValidConfig: false, failureIdx: 6 }
|
|
737
695
|
}
|
|
738
696
|
|
|
739
|
-
/*
|
|
697
|
+
/*
|
|
698
|
+
* If rum is enabled, but then later disabled on the server,
|
|
740
699
|
* this is the only parameter that gets updated.
|
|
741
700
|
*
|
|
742
701
|
* This condition should only be met if rum is disabled during
|
|
743
702
|
* the lifetime of an application, and it should be picked up
|
|
744
703
|
* on the next ForceRestart by the collector.
|
|
745
704
|
*/
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
return _gracefail(7)
|
|
705
|
+
if (config.browser_monitoring.loader === 'none') {
|
|
706
|
+
return { isValidConfig: false, failureIdx: 7 }
|
|
749
707
|
}
|
|
750
708
|
|
|
709
|
+
if (!allowTransactionlessInjection && !transaction) {
|
|
710
|
+
return { isValidConfig: false, failureIdx: 1 }
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
return { isValidConfig: true }
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Get the script header necessary for Browser Monitoring
|
|
718
|
+
* This script must be manually injected into your templates, as high as possible
|
|
719
|
+
* in the header, but _after_ any X-UA-COMPATIBLE HTTP-EQUIV meta tags.
|
|
720
|
+
* Otherwise you may hurt IE!
|
|
721
|
+
*
|
|
722
|
+
* By default this method will return a script wrapped by `<script>` tags, but with
|
|
723
|
+
* option `hasToRemoveScriptWrapper` it can send back only the script content
|
|
724
|
+
* without the `<script>` wrapper. Useful for React component based frontend.
|
|
725
|
+
*
|
|
726
|
+
* This method must be called every time you want to generate the headers.
|
|
727
|
+
*
|
|
728
|
+
* Do *not* reuse the headers between users, or even between requests.
|
|
729
|
+
*
|
|
730
|
+
* @param {object} options configuration options
|
|
731
|
+
* @param {string} [options.nonce] - Nonce to inject into `<script>` header.
|
|
732
|
+
* @param {boolean} [options.hasToRemoveScriptWrapper] - Used to import agent script without `<script>` tag wrapper.
|
|
733
|
+
* @param {options} [options.allowTransactionlessInjection] Whether or not to allow the Browser Agent to be injected when there is no active transaction
|
|
734
|
+
* @returns {string} The script content to be injected in `<head>` or put inside `<script>` tag (depending on options)
|
|
735
|
+
*/
|
|
736
|
+
API.prototype.getBrowserTimingHeader = function getBrowserTimingHeader(options = {}) {
|
|
737
|
+
const metric = this.agent.metrics.getOrCreateMetric(
|
|
738
|
+
NAMES.SUPPORTABILITY.API + '/getBrowserTimingHeader'
|
|
739
|
+
)
|
|
740
|
+
metric.incrementCallCount()
|
|
741
|
+
|
|
742
|
+
const trans = this.agent.getTransaction()
|
|
743
|
+
|
|
744
|
+
const { isValidConfig, failureIdx, quietMode } = validateBrowserMonitoring(
|
|
745
|
+
this.agent.config,
|
|
746
|
+
trans,
|
|
747
|
+
options.allowTransactionlessInjection
|
|
748
|
+
)
|
|
749
|
+
|
|
750
|
+
if (!isValidConfig) {
|
|
751
|
+
return _gracefail(failureIdx, quietMode)
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
const config = this.agent.config
|
|
755
|
+
|
|
751
756
|
// This hash gets written directly into the browser.
|
|
752
757
|
const rumHash = {
|
|
753
|
-
agent:
|
|
754
|
-
beacon:
|
|
755
|
-
errorBeacon:
|
|
756
|
-
licenseKey:
|
|
757
|
-
applicationID:
|
|
758
|
-
applicationTime: time,
|
|
759
|
-
transactionName: hashes.obfuscateNameUsingKey(name, key),
|
|
760
|
-
queueTime: trans.queueTime,
|
|
761
|
-
ttGuid: trans.id,
|
|
758
|
+
agent: config.browser_monitoring.js_agent_file,
|
|
759
|
+
beacon: config.browser_monitoring.beacon,
|
|
760
|
+
errorBeacon: config.browser_monitoring.error_beacon,
|
|
761
|
+
licenseKey: config.browser_monitoring.browser_key,
|
|
762
|
+
applicationID: config.application_id,
|
|
762
763
|
|
|
763
764
|
// we don't use these parameters yet
|
|
764
765
|
agentToken: null
|
|
765
766
|
}
|
|
766
767
|
|
|
767
|
-
const
|
|
768
|
+
const hasActiveTransaction = trans !== null
|
|
768
769
|
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
770
|
+
if (hasActiveTransaction) {
|
|
771
|
+
// bail gracefully outside an ignored transaction
|
|
772
|
+
if (trans.isIgnored()) {
|
|
773
|
+
return _gracefail(1)
|
|
774
|
+
}
|
|
773
775
|
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
776
|
+
/* If we're in an unnamed transaction, add a friendly warning this is to
|
|
777
|
+
* avoid people going crazy, trying to figure out why browser monitoring is
|
|
778
|
+
* not working when they're missing a transaction name.
|
|
779
|
+
*/
|
|
780
|
+
const name = trans.getFullName()
|
|
781
|
+
if (!name) {
|
|
782
|
+
return _gracefail(3)
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
const time = trans.timer.getDurationInMillis()
|
|
786
|
+
rumHash.applicationTime = time
|
|
787
|
+
|
|
788
|
+
/*
|
|
789
|
+
* Only the first 13 chars of the license should be used for hashing with
|
|
790
|
+
* the transaction name.
|
|
791
|
+
*/
|
|
792
|
+
const key = config.license_key.substr(0, 13)
|
|
793
|
+
rumHash.transactionName = hashes.obfuscateNameUsingKey(name, key)
|
|
778
794
|
|
|
779
|
-
|
|
780
|
-
rumHash.
|
|
795
|
+
rumHash.queueTime = trans.queueTime
|
|
796
|
+
rumHash.ttGuid = trans.id
|
|
797
|
+
|
|
798
|
+
const attrs = Object.create(null)
|
|
799
|
+
|
|
800
|
+
const customAttrs = trans.trace.custom.get(ATTR_DEST.BROWSER_EVENT)
|
|
801
|
+
if (!properties.isEmpty(customAttrs)) {
|
|
802
|
+
attrs.u = customAttrs
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
const agentAttrs = trans.trace.attributes.get(ATTR_DEST.BROWSER_EVENT)
|
|
806
|
+
if (!properties.isEmpty(agentAttrs)) {
|
|
807
|
+
attrs.a = agentAttrs
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
if (!properties.isEmpty(attrs)) {
|
|
811
|
+
rumHash.atts = hashes.obfuscateNameUsingKey(JSON.stringify(attrs), key)
|
|
812
|
+
}
|
|
813
|
+
} else {
|
|
814
|
+
logger.debug(
|
|
815
|
+
'No transaction detected when generating RUM header, continuing without transaction info'
|
|
816
|
+
)
|
|
781
817
|
}
|
|
782
818
|
|
|
783
819
|
// if debugging, do pretty format of JSON
|
|
@@ -785,7 +821,11 @@ API.prototype.getBrowserTimingHeader = function getBrowserTimingHeader(options)
|
|
|
785
821
|
const json = JSON.stringify(rumHash, null, tabs)
|
|
786
822
|
|
|
787
823
|
// the complete header to be written to the browser
|
|
788
|
-
const out = _generateRUMHeader(
|
|
824
|
+
const out = _generateRUMHeader(
|
|
825
|
+
{ nonce: options.nonce, hasToRemoveScriptWrapper: options.hasToRemoveScriptWrapper },
|
|
826
|
+
json,
|
|
827
|
+
config.browser_monitoring.js_agent_loader
|
|
828
|
+
)
|
|
789
829
|
|
|
790
830
|
logger.trace('generating RUM header', out)
|
|
791
831
|
|