AppDynamics EUM JavaScript Injection for Selective URLs

Problem this snippet solves:

This code allows for the adrum.js agent to be dynamically injected into an application to support collecting EUM metrics. With this code, you can select from any number of HTTP Request headers and/or POST parameters.

Additional EUM features in use:

  • Custom GeoIP mappings based on a DataGroup
  • User Data for Browser Snapshots, currently APM SID and Username

How to use this snippet:

This sample iRule assumes that the TCL variables $username and $sid have been previously created to support the UserData injection. If you don't have this information or APM available then these lines should be commented out or changed to meet your needs.

Import the ltm profiles and iRule via

tmsh load sys config merge <from-terminal>

On your virtual, attache the Head-HTML profile as well as the iRule.

Code :

LTM Profiles Required:

ltm html-rule tag-raise-event HTMLEvent-HeadStart-HTMLRule {
    description "Match an HTML tag for "
    match {
        tag-name head
    }
}
ltm profile html Head-HTML {
    app-service none
    content-detection disabled
    content-selection { text/html text/xhtml }
    defaults-from html
    description none
    rules {
        HTMLEvent-HeadStart-HTMLRule
    }
}

iRule to be attached to the Virtual:
ltm rule SND-AppDynamics-HTML-Rule {

when CLIENT_ACCEPTED {
    set APPDYNAMICS_EUM_DEBUG 0;
}

when HTTP_REQUEST {
    set APPDYNAMICS_EUM_APP_ID "AD-xxx-xxx-xxx-xxx"
    if { $APPDYNAMICS_EUM_DEBUG > 0 } {set uri [HTTP::uri]}
    
    if {[HTTP::uri] starts_with "/my/HomePage.do"} {
        # set enableEum 1
        if { [HTTP::header Content-Type] eq "application/x-www-form-urlencoded" } {
            # HTTP::collect [HTTP::header Content-Length]
            # Only collect the first 200 bytes which should be enough to capture eventSource
            HTTP::collect 200
        } else {
            if {[HTTP::uri] starts_with "/my/defaultPage"} {
                set enableEum 1
            }
        }
    } elseif {[HTTP::uri] starts_with "/app1"} {
        set enableEum 1
    } elseif {[HTTP::uri] starts_with "/app2"} {
        set enableEum 1
}

when HTTP_REQUEST_DATA {
    set namevals [split [HTTP::payload] "&"]
    for {set i 0} {$i < [llength $namevals]} {incr i} {
        set params [split [lindex $namevals $i] "="]
        # log local0. "    [lindex $params 0] : [lindex $params 1]"
        if {[lindex $params 0] equals "eventSource"} {
            switch -glob [lindex $params 1] {
                "PostParm1" -
                "PostParm2" -
                "PostParm3" {
                    set enableEum 1
                    if { $APPDYNAMICS_EUM_DEBUG > 0 } { log local0. "FOUND HTTP DATA [lindex $params 1] TO ENABLE APPDYNAMICS EUM"; }
                }
            }
            break;
        }
        unset params
    }
    unset namevals
}

when HTTP_RESPONSE {
    if {[info exists enableEum]} {
        if { ($enableEum == 1) && ([HTTP::header "Content-Type"] starts_with "text/html") } {
            HTML::enable
            set enableEum 0
        } else {
            HTML::disable
        }
    } else {
        HTML::disable
    }
}

when HTML_TAG_MATCHED {
    if { $APPDYNAMICS_EUM_DEBUG > 0 } { log local0. "uri = $uri element = [HTML::tag name] attribute id = [HTML::tag attribute id]"}
    
    switch [HTML::tag name] {
        "head" {
            if { $APPDYNAMICS_EUM_DEBUG > 0 } { log local0. "$uri info username [info exists username] info sid [info exists sid]"}
            if {([info exists username]) && ([info exists sid])} {
                # Send custom GeoIP Data to with the adrum beacon if we are on the private network
                set geoData [split [class match -value [IP::client_addr] equals Branch-Address-DataGroup ] "/"]
                if { $geoData != "" } {
                    HTML::tag append [subst {



                    } ]
                } else {
                    HTML::tag append [subst {



                    } ]
                }
                unset geoData
            }
        }
    }
}
}

Tested this on version:

11.5
Updated Jun 06, 2023
Version 2.0

Was this article helpful?

No CommentsBe the first to comment