Skip to content

Commit de5a8ba

Browse files
authored
Merge pull request #54 from instana/eum-snippet
EUM Helper & Tests
2 parents 709b9e9 + 8f95039 commit de5a8ba

File tree

6 files changed

+231
-0
lines changed

6 files changed

+231
-0
lines changed

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,31 @@ If you use uWSGI in forking workers mode, you must specify `--lazy-apps` (or `la
5757

5858
The instana package will automatically collect key metrics from your Python processes. Just install and go.
5959

60+
## Want End User Monitoring?
61+
62+
Instana provides deep end user monitoring that links server side traces with browser events to give you a complete view from server to browser.
63+
64+
For Python templates and views, get your EUM API key from your Instana dashboard and you can call `instana.helpers.eum_snippet(api_key='abc')` from within your layout file. This will output
65+
a small javascript snippet of code to instrument browser events. It's based on [Weasel](https://github.com/instana/weasel). Check it out.
66+
67+
As an example, you could do the following:
68+
69+
```python
70+
from instana.helpers import eum_snippet
71+
72+
instana.api_key = 'abc'
73+
meta_kvs = { 'username': user.name }
74+
75+
# This will return a string containing the EUM javascript for the layout or view.
76+
eum_snippet(meta=meta_kvs)
77+
```
78+
79+
The optional second argument to `eum_snippet()` is a hash of metadata key/values that will be reported along with the browser instrumentation.
80+
81+
![Instana EUM example with metadata](https://s3.amazonaws.com/instana/Instana+Gameface+EUM+with+metadata+2016-12-22+at+15.32.01.png)
82+
83+
See also the [End User Monitoring](https://docs.instana.io/products/website_monitoring/#configuration) in the Instana documentation portal.
84+
6085
## OpenTracing
6186

6287
This Python package supports [OpenTracing](http://opentracing.io/). When using this package, the OpenTracing tracer (`opentracing.tracer`) is automatically set to the `InstanaTracer`.

instana/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,8 @@
5858
# instana.service_name = "myservice"
5959
service_name = None
6060

61+
# User configurable EUM API key for instana.helpers.eum_snippet()
62+
eum_api_key = ''
63+
6164
if "INSTANA_SERVICE_NAME" in os.environ:
6265
service_name = os.environ["INSTANA_SERVICE_NAME"]

instana/eum.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script>
2+
(function(i,s,o,g,r,a,m){i['InstanaEumObject']=r;i[r]=i[r]||function(){
3+
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
4+
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
5+
})(window,document,'script','//eum.instana.io/eum.min.js','ineum');
6+
ineum('apiKey', '$eum_api_key');
7+
ineum('traceId', '$trace_id');
8+
9+
$meta_kvs
10+
</script>

instana/eum_test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script nonce="68afd870-ae85-48c6-9689-9a5c359d5a1f">
2+
(function(i,s,o,g,r,a,m){i['InstanaEumObject']=r;i[r]=i[r]||function(){
3+
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
4+
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
5+
})(window,document,'script','//eum-test-fullstack-0-us-west-2.instana.io/eum.min.js','ineum');
6+
7+
ineum('reportingUrl', '//eum-test-fullstack-0-us-west-2.instana.io');
8+
ineum('apiKey', '$eum_api_key');
9+
ineum('traceId', '$trace_id');
10+
11+
$meta_kvs
12+
</script>

instana/helpers.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import os
2+
from string import Template
3+
from instana import internal_tracer, eum_api_key as global_eum_api_key
4+
from instana.log import logger
5+
6+
# Usage:
7+
#
8+
# from instana.helpers import eum_snippet
9+
# meta_kvs = { 'userId': user.id }
10+
# eum_snippet(meta=meta_kvs)
11+
12+
13+
def eum_snippet(trace_id=None, eum_api_key=None, meta={}):
14+
"""
15+
Return an EUM snippet for use in views, templates and layouts that reports
16+
client side metrics to Instana that will automagically be linked to the
17+
current trace.
18+
19+
@param trace_id [optional] the trace ID to insert into the EUM string
20+
@param eum_api_key [optional] the EUM API key from your Instana dashboard
21+
@param meta [optional] optional additional KVs you want reported with the
22+
EUM metrics
23+
24+
@return string
25+
"""
26+
try:
27+
eum_file = open(os.path.dirname(__file__) + '/eum.js')
28+
eum_src = Template(eum_file.read())
29+
30+
# Prepare the standard required IDs
31+
ids = {}
32+
ids['meta_kvs'] = ''
33+
34+
current_ctx = internal_tracer.current_context()
35+
36+
if trace_id or current_ctx:
37+
ids['trace_id'] = trace_id or current_ctx.trace_id
38+
else:
39+
# No trace_id passed in and tracer doesn't show an active span so
40+
# return nothing, nada & zip.
41+
return ''
42+
43+
if eum_api_key:
44+
ids['eum_api_key'] = eum_api_key
45+
else:
46+
ids['eum_api_key'] = global_eum_api_key
47+
48+
# Process passed in EUM 'meta' key/values
49+
for key, value in meta.items():
50+
ids['meta_kvs'] += ("'ineum('meta', '%s', '%s');'" % (key, value))
51+
52+
return eum_src.substitute(ids)
53+
except Exception as e:
54+
logger.debug(e)
55+
return ''
56+
57+
def eum_test_snippet(trace_id=None, eum_api_key=None, meta={}):
58+
"""
59+
Return an EUM snippet for use in views, templates and layouts that reports
60+
client side metrics to Instana that will automagically be linked to the
61+
current trace.
62+
63+
@param trace_id [optional] the trace ID to insert into the EUM string
64+
@param eum_api_key [optional] the EUM API key from your Instana dashboard
65+
@param meta [optional] optional additional KVs you want reported with the
66+
EUM metrics
67+
68+
@return string
69+
"""
70+
71+
try:
72+
eum_file = open(os.path.dirname(__file__) + '/eum_test.js')
73+
eum_src = Template(eum_file.read())
74+
75+
# Prepare the standard required IDs
76+
ids = {}
77+
ids['meta_kvs'] = ''
78+
79+
current_ctx = internal_tracer.current_context()
80+
81+
if trace_id or current_ctx:
82+
ids['trace_id'] = trace_id or current_ctx.trace_id
83+
else:
84+
# No trace_id passed in and tracer doesn't show an active span so
85+
# return nothing, nada & zip.
86+
return ''
87+
88+
if eum_api_key:
89+
ids['eum_api_key'] = eum_api_key
90+
else:
91+
ids['eum_api_key'] = global_eum_api_key
92+
93+
# Process passed in EUM 'meta' key/values
94+
for key, value in meta.items():
95+
ids['meta_kvs'] += ("'ineum('meta', '%s', '%s');'" % (key, value))
96+
97+
return eum_src.substitute(ids)
98+
except Exception as e:
99+
logger.debug(e)
100+
return ''

tests/test_helpers.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
from nose.tools import assert_equals
2+
from instana.helpers import eum_snippet, eum_test_snippet
3+
4+
# fake trace_id to test against
5+
trace_id = "aMLx9G2GnnQ6QyMCLJLuCM8nw"
6+
# fake api key to test against
7+
eum_api_key = "FJB66VjwGgGQX6jiCpekoR4vf"
8+
9+
# fake meta key/values
10+
meta1 = "Z7RmMKQAiyCLEAmseNy7e6Vm4"
11+
meta2 = "Dp2bowfm6kJVD9CccmyBt4ePD"
12+
meta3 = "N4poUwbNz98YcvWRAizy2phCo"
13+
14+
15+
def test_vanilla_eum_snippet():
16+
eum_string = eum_snippet(trace_id=trace_id, eum_api_key=eum_api_key)
17+
assert type(eum_string) is str
18+
19+
assert eum_string.find(trace_id) != -1
20+
assert eum_string.find(eum_api_key) != -1
21+
22+
def test_eum_snippet_with_meta():
23+
meta_kvs = {}
24+
meta_kvs['meta1'] = meta1
25+
meta_kvs['meta2'] = meta2
26+
meta_kvs['meta3'] = meta3
27+
28+
eum_string = eum_snippet(trace_id=trace_id, eum_api_key=eum_api_key, meta=meta_kvs)
29+
assert type(eum_string) is str
30+
31+
assert eum_string.find(trace_id) != -1
32+
assert eum_string.find(eum_api_key) != -1
33+
assert eum_string.find(meta1) != -1
34+
assert eum_string.find(meta2) != -1
35+
assert eum_string.find(meta3) != -1
36+
37+
def test_eum_snippet_error():
38+
meta_kvs = {}
39+
meta_kvs['meta1'] = meta1
40+
meta_kvs['meta2'] = meta2
41+
meta_kvs['meta3'] = meta3
42+
43+
# No active span on tracer & no trace_id passed in.
44+
eum_string = eum_snippet(eum_api_key=eum_api_key, meta=meta_kvs)
45+
assert_equals('', eum_string)
46+
47+
def test_vanilla_eum_test_snippet():
48+
eum_string = eum_test_snippet(trace_id=trace_id, eum_api_key=eum_api_key)
49+
assert type(eum_string) is str
50+
51+
assert eum_string.find(trace_id) != -1
52+
assert eum_string.find(eum_api_key) != -1
53+
assert eum_string.find('reportingUrl') != -1
54+
assert eum_string.find('//eum-test-fullstack-0-us-west-2.instana.io') != -1
55+
56+
def test_eum_test_snippet_with_meta():
57+
meta_kvs = {}
58+
meta_kvs['meta1'] = meta1
59+
meta_kvs['meta2'] = meta2
60+
meta_kvs['meta3'] = meta3
61+
62+
eum_string = eum_test_snippet(trace_id=trace_id, eum_api_key=eum_api_key, meta=meta_kvs)
63+
assert type(eum_string) is str
64+
assert eum_string.find('reportingUrl') != -1
65+
assert eum_string.find('//eum-test-fullstack-0-us-west-2.instana.io') != -1
66+
67+
assert eum_string.find(trace_id) != -1
68+
assert eum_string.find(eum_api_key) != -1
69+
assert eum_string.find(meta1) != -1
70+
assert eum_string.find(meta2) != -1
71+
assert eum_string.find(meta3) != -1
72+
73+
def test_eum_test_snippet_error():
74+
meta_kvs = {}
75+
meta_kvs['meta1'] = meta1
76+
meta_kvs['meta2'] = meta2
77+
meta_kvs['meta3'] = meta3
78+
79+
# No active span on tracer & no trace_id passed in.
80+
eum_string = eum_test_snippet(eum_api_key=eum_api_key, meta=meta_kvs)
81+
assert_equals('', eum_string)

0 commit comments

Comments
 (0)