Skip to content

Commit

Permalink
Merge pull request #155 from namecheap/feature/RND-326
Browse files Browse the repository at this point in the history
Feature/rnd 326: Added ability to wrap NewRelic client side JS with custom wrapper
  • Loading branch information
StyleT authored May 6, 2020
2 parents a70ac8b + 5d7995e commit 2b3a9cd
Show file tree
Hide file tree
Showing 7 changed files with 33 additions and 8 deletions.
6 changes: 6 additions & 0 deletions docs/installation_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,11 @@ ILC supports integration with [NewRelic APM](https://newrelic.com/products/appli

To turn it on you need to pass your NewRelic license key in `NR_LICENSE_KEY` env variable to ILC & Registry containers.

You can also wrap JS code that NR will generate if you have NewRelic Browser product enabled via `NR_CUSTOM_CLIENT_JS_WRAPPER`
env variable. This may be useful for the compliance with GDPR customer settings. Example of usage:
```html
<script type="text/javascript">(function mygdprWrapper(){ %CONTENT% })()</script>`
```

Custom metrics sent to Insights:
* PageAction with Action Name `routeChange`. It contains duration of the reroute in ms.
1 change: 1 addition & 0 deletions ilc/config/custom-environment-variables.json5
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
},
newrelic: {
licenseKey: 'NR_LICENSE_KEY',
customClientJsWrapper: 'NR_CUSTOM_CLIENT_JS_WRAPPER',
},
overrideConfigTrustedOrigins: 'OVERRIDE_CONFIG_TRUSTED_ORIGINS'
}
4 changes: 4 additions & 0 deletions ilc/config/default.json5
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
},
newrelic: {
licenseKey: null,
/**
* Usage example: <script type="text/javascript">(function mygdprWrapper(){ %CONTENT% })()</script>
*/
customClientJsWrapper: null,
},
overrideConfigTrustedOrigins: null
}
4 changes: 2 additions & 2 deletions ilc/config/development.json5
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
productionMode: false
}
productionMode: false
}
2 changes: 1 addition & 1 deletion ilc/server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const errorHandler = require('./errorHandler');

app.register(require('./ping'));

const tailor = tailorFactory(config.get('cdnUrl'));
const tailor = tailorFactory(config.get('cdnUrl'), config.get('newrelic.customClientJsWrapper'));

if (config.get('cdnUrl') === null) {
app.use('/_ilc/', serveStatic(config.get('productionMode')));
Expand Down
20 changes: 17 additions & 3 deletions ilc/server/tailor/configs-injector.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ const urljoin = require('url-join');
const newrelic = require('newrelic');

module.exports = class ConfigsInjector {
#nrCustomClientJsWrapper;
#cdnUrl;
#jsInjectionPlaceholder = '<!-- ILC_JS -->';
#cssInjectionPlaceholder = '<!-- ILC_CSS -->';

constructor(cdnUrl = null) {
constructor(cdnUrl = null, nrCustomClientJsWrapper = null) {
this.#cdnUrl = cdnUrl;
this.#nrCustomClientJsWrapper = nrCustomClientJsWrapper;
}

inject(request, registryConfig, template, slots) {
Expand All @@ -35,7 +37,7 @@ module.exports = class ConfigsInjector {
`<script>window.ilcApps = [];</script>`,
this.#getPolyfill(),
this.#wrapWithAsyncScriptTag(this.#getClientjsUrl()),
newrelic.getBrowserTimingHeader(),
this.#getNewRelicScript(),
);

if (document.includes(this.#jsInjectionPlaceholder)) {
Expand Down Expand Up @@ -154,11 +156,23 @@ module.exports = class ConfigsInjector {

#wrapWithFragmentStylesheetLink = (url, fragmentId) => {
return `<link rel="stylesheet" href="${url}" data-fragment-id="${fragmentId}">`;
}
};

#getCrossoriginAttribute = (url) => {
return (this.#cdnUrl !== null && url.includes(this.#cdnUrl)) || url.includes('://') ? 'crossorigin' : '';
};

#wrapWithIgnoreDuringParsing = (...content) => `<!-- TailorX: Ignore during parsing START -->${content.join('')}<!-- TailorX: Ignore during parsing END -->`;

#getNewRelicScript = () => {
let nrCode = newrelic.getBrowserTimingHeader();

if (this.#nrCustomClientJsWrapper === null || !nrCode) {
return nrCode;
}

nrCode = nrCode.replace(/<script.*?>(.*)<\/script\s*>/s, '$1');

return this.#nrCustomClientJsWrapper.replace('%CONTENT%', nrCode);
}
};
4 changes: 2 additions & 2 deletions ilc/server/tailor/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ const fragmentHooks = require('./fragment-hooks');
const ConfigsInjector = require('./configs-injector');


module.exports = function (cdnUrl) {
module.exports = function (cdnUrl, nrCustomClientJsWrapper = null) {
const router = new Router(console);
const configsInjector = new ConfigsInjector(cdnUrl);
const configsInjector = new ConfigsInjector(cdnUrl, nrCustomClientJsWrapper);

const tailor = new Tailor({
fetchTemplate: fetchTemplate(
Expand Down

0 comments on commit 2b3a9cd

Please sign in to comment.