This page describes how to instrument a browser application using Apache to automatically inject the JavaScript Agent. If you are using Apache as your web container, or you are currently using, or willing to use, Apache as a reverse proxy, you can use a container substitution module to automatically inject the JavaScript Agent into your pages. The module intercepts the response object as it is being returned and makes a string substitution.

This method uses the two Apache modules mod_substitute and mod_filter.

Download the Agent

You must first download the JavaScript Agent from the Browser Monitoring configuration pane.

  1. Open the browser application in which you are interested.

  2. From the left navigation menu, select Configuration

  3. Click the Configure and download JavaScript Agent.

  4. For the JavaScript hosting option, select I will host all the JavaScript agent files.

  5. Click Download to download the JavaScript Agent.

  6. Place the file somewhere accessible to the Apache instance. The name of the saved file should be adrum.js.

Configure Apache

The basic configuration procedure includes: 

  1. Make Sure the Modules are Loaded
  2. Create an Adrum Configuration File
  3. Add the Location of the Adrum Configuration File to httpd.conf
  4. Restart the Web Server

Make Sure the Modules are Loaded

Check your global Apache httpd.conf file and make sure that the following two LoadModule commands are in the file:

LoadModule substitute_module modules/mod_substitute.so
LoadModule filter_module modules/mod_filter.so

Create an Adrum Configuration File

Create a file named adrum.conf with contents similar to the example below, based on your Apache version. (See this Stack Overflow post for details.) In this case, the substitution rule covers the location of the entire site (Location /) but you can also recursively select a specific directory and its subdirectories by using /somedirectory.  

Sample adrum.conf Apache 2.2

Replace the sample code below with your own JavaScript Agent script.

<Location "/">
    SetOutputFilter INFLATE;SUBSTITUTE;DEFLATE 
    AddOutputFilterByType SUBSTITUTE text/html
    Substitute "s#<head>#<head><script>window['adrum-start-time'] = new Date().getTime();</script><script>(function(config){config.appKey='<EUM_APP_KEY>';})(window['adrum-config'] || (window['adrum-config'] = {}));</script><script src='./adrum.js'></script>#inq"
</Location>
XML

If you use <meta> tags, you should place them right after your <head> tag, and then place the JavaScript Agent directly after the last <meta> tag and before other <script> tags. This can avoid issues with some versions of IE and improve the accuracy of the resource timing.

Sample adrum.conf Apache 2.4 

Replace the sample code below with your own JavaScript Agent script.

<Location "/">
    AddOutputFilterByType SUBSTITUTE text/html
    Substitute "s#<head>#<head><script>window['adrum-start-time'] = new Date().getTime();</script><script>(function(config){config.appKey='<EUM_APP_KEY>';})(window['adrum-config'] || (window['adrum-config'] = {}));</script><script src='./adrum.js'></script>#inq"
</Location>
XML

Where ./adrum.js is the path to a copy of the adrum file that is accessible to the server. The flags after the # are:

  • i -  matching is case-insensitive
  • n -  pattern is treated as a fixed string (removing the n means the pattern is treated as a regular expression) 
  • q - module does not flatten the buckets after each substitution - this can speed performance.  

For more information, see the Apache module docs here.  

If your <head> tag has an attribute like <head lang="en">, you can use a regex in the substitution string and omit the n flag. Replace the sample code below with your own JavaScript Agent script.

Substitute "s#(<head[^>]*>)#$1<script>window['adrum-start-time'] = new Date().getTime();</script><script>(function(config){config.appKey='<EUM_APP_KEY>';})(window['adrum-config'] || (window['adrum-config'] = {}));</script><script src='./adrum.js'></script>#iq"
TEXT

Note the timer initialization: <script>window['adrum-start-time'] = new Date().getTime();</script>. Injecting these scripts as close as possible to the top of the document, preferably right after the <head> tag, ensures the best possible timings.

Also, if you use <meta> tags, you should place them right after your <head> tag, and then place the JavaScript Agent directly after the last <meta> tag and before other <script> tags. This can avoid issues with some versions of IE and again improve the accuracy of the resource timing.


(Optional) Adjust for gzipped resources

If your page is compressed, the substitution won't work unless the content is INFLATEd, the substitution is made, and then the content is DEFLATEd. There are multiple ways to do this. For example, in the FilterProvider line:

FilterProvider AdrumFilter INFLATE;SUBSTITUTE;DEFLATE resp=Content-Type $text/html

See this Stack Overflow post for more information. If you are using Apache as a proxy, you can also instruct it not to accept gzip-encoded content.

Add the Location of the Adrum Configuration File to httpd.conf

Add the following line to your global Apache httpd.conf file:

Include [absolutePathTo]/adrum.conf

Alternatively, you can add the directives to the httpd.conf file directly instead of creating a separate adrum file.

Restart the Web Server

To pick up the new configuration, restart:

sudo apchectl -k restart

 If you get a warning "Useless use of AllowOverride in line 2 of [absolutePathTo]/adrum.conf", it can be ignored.  It simply means AllowOverride is redundant. You can remove it if you wish.

Possible variations on the script string can be found in Configure the JavaScript Agent.

Other Alternatives

If you are setting up your automatic injection using an Apache instance that is configured as a reverse proxy, you must use the Location directive method described above, with the ProxyPass and ProxyPassReverse directives also in the Location directive. If you are using an Apache instance that is your primary web container you have two additional options for describing the actual substitution step:

Use the Directory Directive

You can use the Directory directive instead of the Location directive.  

Use .htaccess 

Add lines similar to this to an .htaccess file in the base document directory for your site, replacing your filter name for <MyFilter>. If you don't have an .htaccess file, create one:

Apache 2.2

Replace the sample code below with your own JavaScript Agent script.

Substitute "s#<head>#<head><script>window['adrum-start-time'] = new Date().getTime();</script><script>(function(config){config.appKey='<EUM_APP_KEY>';})(window['adrum-config'] || (window['adrum-config'] = {}));</script><script src='./adrum.js'></script>#inq"
TEXT
AllowOverride Options
FilterDeclare <MyFilter>
FilterProvider <MyFilter> SUBSTITUTE resp=Content-Type $text/html
FilterChain <MyFilter>
Substitute "s#<head>#<head><script>window['adrum-start-time'] = new Date().getTime();</script><script>(function(config){config.appKey='<EUM_APP_KEY>';})(window['adrum-config'] || (window['adrum-config'] = {}));</script><script src='./adrum.js'></script>#inq"
TEXT


Apache 2.4

Replace the sample code below with your own JavaScript Agent script.

Substitute "s#<head>#<head><script>window['adrum-start-time'] = new Date().getTime();</script><script>(function(config){config.appKey='<EUM_APP_KEY>';})(window['adrum-config'] || (window['adrum-config'] = {}));</script><script src='./adrum.js'></script>#inq"
TEXT
AddOutputFilterByType SUBSTITUTE text/html
Substitute "s#<head>#<head><script>window['adrum-start-time'] = new Date().getTime();</script><script>(function(config){config.appKey='<EUM_APP_KEY>';})(window['adrum-config'] || (window['adrum-config'] = {}));</script><script src='./adrum.js'></script>#inq"
TEXT

Where ./adrum.js is the path to a copy of the adrum file that is accessible to the server. Make sure .htaccess is world-readable.