From 6576b3714f11f6b0d9a013b125d4f2e6693981da Mon Sep 17 00:00:00 2001 From: Les Orchard Date: Tue, 7 Jun 2016 16:57:39 -0400 Subject: [PATCH] Add /api/metrics/testpilottest POST resource - /api/metrics/testpilottest accepts POST'd JSON body which gets included in the Fields property of a [mozlog log event][mozlog] - Add django-cors-headers dependency to allow CORS requests to the API - Tiny WebExtension example in docs/examples/webextension to show how to POST to the metrics ping resource - Tests [mozlog]: https://github.com/mozilla-services/Dockerflow/blob/master/docs/mozlog.md Issue #433 --- docs/examples/webextension/background.js | 14 +++ docs/examples/webextension/icons/icon-32.png | Bin 0 -> 2388 bytes docs/examples/webextension/manifest.json | 19 ++++ requirements.txt | 2 + testpilot/metrics/__init__.py | 0 testpilot/metrics/tests.py | 90 +++++++++++++++++++ testpilot/metrics/urls.py | 8 ++ testpilot/metrics/views.py | 30 +++++++ testpilot/settings.py | 11 +++ testpilot/urls.py | 1 + 10 files changed, 175 insertions(+) create mode 100644 docs/examples/webextension/background.js create mode 100644 docs/examples/webextension/icons/icon-32.png create mode 100644 docs/examples/webextension/manifest.json create mode 100644 testpilot/metrics/__init__.py create mode 100644 testpilot/metrics/tests.py create mode 100644 testpilot/metrics/urls.py create mode 100644 testpilot/metrics/views.py diff --git a/docs/examples/webextension/background.js b/docs/examples/webextension/background.js new file mode 100644 index 0000000000..e2dac4b000 --- /dev/null +++ b/docs/examples/webextension/background.js @@ -0,0 +1,14 @@ +fetch('https://testpilot.firefox.com/api/metrics/ping/testpilottest', { + method: 'POST', + mode: 'cors', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({ + "some": "random", + "metrics": "ping", + "payload": "here" + }) +}).then(resp => { + console.log('metrics ping success', resp); +}).catch(e => { + console.log('problem sending metrics ping', e); +}); diff --git a/docs/examples/webextension/icons/icon-32.png b/docs/examples/webextension/icons/icon-32.png new file mode 100644 index 0000000000000000000000000000000000000000..48cc3422199acf1fe9f1ec2f19ad4f2a3a4a2951 GIT binary patch literal 2388 zcmV-a39I&rP)=rUaFMEHNPo2{1`!GTZlk@4fy(7$s!U)82FDpZV^) zzx(d}-Q^MVAlW5l2#FXXK;6d{PHn#U|250j=QsJ=2egKC)gnu(O;LqU4}YC^b>^N8 z)AH*vW{NcAj*0y6-a}&I6^SS>UeqlHK`-JeTxRhsT@XquURA6!KGz%8U8*EOro<3{ z5CR~8pp=wyv)7}Uc7tC`QN@!O8>cVF28O4Tlo0CyLxxv`qi((6AB^8 z>5xCaf0~)JWcl+UlRYj|8an3>XapcLMh-=qGX^$`3X3e`d>{yaD2(^NJ%*EYjc_Np zbiZz>PK&nv`J2by{>Zk^alU9lpw|c_7p*{JZ38kg(rj*<8hz}Xw-$izX=#m`kuws7 z<8MSpoD%{9I^!T61_S^C0!5+#fa2{tQTXvTB)VdakZCCW9F9A`d1CInJv#8@N83=c zYafh2&^jnJ<%)(j-?y?vh1(WIc0V`^4vPu^poAc7vdcmz04NfTeAi?N4}G{5Ybq*X zjk2PT-M00_Q}b`_)`3wg|AxJ%>MS`|rl%inZa(4*hEY6W44%rp9zqBZ@*`wn`3_JJ zkdC_xA)qscg52xivRWd#2IFY(`f&C0rI08IBspvqCl}411OS-!2=K2fk2-mS7MLO@q^_p{~V?Xp4q5`L`f9GaVA85#5ks zBFq?Eg(XmB2?OHerXOlJ^N(bUCD`!n#(To?%{)Q@2Fv2 zf*XusZT@%|Cc_O^^uvnV#=&3=xtZy>xf3`5SQHtmB;mxO2N4Q}aQuAB#{9tpY}sjj zC;-T*&KS4~ODr~3p6dM9rH*v&JP(qOTm$f(2+|rHF zjB^aUGOgExA;ZL{)yJ{@cn#{?yjXbCXjl~)`J;v-J}@NQUWB?M7wPuA%rJHS$oVs;~X>J{s^fqC+- z0NnQSJ5VL5M-C-NJ7987C?QFdTt@ny|v=*-lTqiq$mqlvudN{BaK-(LlTT}nh*qFA$iCmPRraO;S{P<}!%O`)jq z_%I|n4s9VF5+R6L3YsEg!@fh8j%L$D>8|}q zNOBvhByH+wpcj|V65$C1aJXO&1}4Ns4o-UcZR|W%huPysBPHGi+Ns-dE)Z>1;0qa% zMZ{%~!ps$~0l@%7>2sIptB*emNun5&-Z#hOe6Re{?t^%0YlX$3Di7$4tr}ap(Q>xv zvB-h)eTU$Pi^Yzrqp)de*K2gAK_JT#Y!(%Y&5BJ2zrob(ED!=bv1JG1>`|sfaOBfD z(<=dh%>Vl*STkh;03dPk@+OH=*T{a!^5$7nFW4?9hFw!5KtFd*GR_e=>p|o4LfBLl zr(3=k^lmDp8TTUB{5sB?}*V{@=5_c{Q;m#1n$ zK_KwU_Jo|YzGw^UV4TDK^fE+gD$-*dlN$Yjii}uiVE<$HAyOyh$4&}^b7UpBGY+3= zI#Kx97ijdgW6d46;@7DupoIRi;ZH7X(5G9y7`A*pY!;0t*=?_U_osQ~0FYSr=H>5# z%;(mk-q#*AvQMAX1N99@9Gb>tN~Maq(~%J$d!gg?vaARIddFHm{jJS-V_y}bG!;qq zsIrrPerQf-{Y$Qu9uot*tORz|)YjZNY>-oD%1O1Cv35bFEPs)uxDKAUZ zX9@}kAxsE?Nw2<(I7!CF8Iv!wFZTqVTe=YdLfbFwb7iNWet0ziBraJtj1V$1CB~6< zJ{U3?=WXdu=c&Dq%>I}V!kvXBYVO7lc=qa7FL_aQCI1B{GskuEqe%<^0000.+)', views.log_ping, name='log-ping'), +) diff --git a/testpilot/metrics/views.py b/testpilot/metrics/views.py new file mode 100644 index 0000000000..da2e923b6b --- /dev/null +++ b/testpilot/metrics/views.py @@ -0,0 +1,30 @@ +import logging + +from django.conf import settings +from django.http import Http404 + +from django.views.decorators.csrf import csrf_exempt +from rest_framework.response import Response +from rest_framework.decorators import permission_classes, api_view + +DEFAULT_LOG_PING_WHITELIST = [ + 'testpilottest' +] + + +@csrf_exempt +@api_view(['POST']) +@permission_classes([]) +def log_ping(request, logger_name): + """Accept and log metrics pings""" + whitelist = getattr(settings, 'LOG_PING_WHITELIST', DEFAULT_LOG_PING_WHITELIST) + if logger_name not in whitelist: + raise Http404 + + extra = {} + if request.user.is_authenticated(): + extra['uid'] = request.user.id + extra.update(request.data) + logging.getLogger(logger_name).info('', extra=extra) + + return Response({'status': 'ok'}) diff --git a/testpilot/settings.py b/testpilot/settings.py index 973106f532..2383ab592e 100644 --- a/testpilot/settings.py +++ b/testpilot/settings.py @@ -69,6 +69,7 @@ def path(*args): 'testpilot.base', 'testpilot.frontend', 'testpilot.users', + 'testpilot.metrics', 'testpilot.experiments', # Third party apps @@ -76,6 +77,7 @@ def path(*args): 'django_cleanup', 'csp', + 'corsheaders', 'colorfield', 'rest_framework', 'storages', @@ -108,6 +110,7 @@ def path(*args): MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.locale.LocaleMiddleware', + 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -423,6 +426,9 @@ def lazy_langs(): 'https://*.mozilla.net', ) +CORS_ORIGIN_ALLOW_ALL = True +CORS_URLS_REGEX = r'^/api/.*$' + LOGGING = { 'version': 1, 'disable_existing_loggers': False, @@ -464,6 +470,11 @@ def lazy_langs(): 'level': config('DJANGO_LOG_LEVEL', default='INFO'), 'propagate': True, }, + 'testpilottest': { + 'handlers': ['console'], + 'level': 'INFO', + 'propagate': True, + }, 'request.summary': { 'handlers': ['console'], 'level': 'INFO', diff --git a/testpilot/urls.py b/testpilot/urls.py index a2b82209c9..b03ef8ec62 100644 --- a/testpilot/urls.py +++ b/testpilot/urls.py @@ -19,6 +19,7 @@ url(r'^admin/', include(admin.site.urls)), url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), + url(r'^api/metrics/', include('testpilot.metrics.urls')), url(r'^api/experiments/', include('testpilot.experiments.urls')), url(r'^api/', include(router.urls)), # Catch-all fallback to frontend client view