UMRUM - Open Source Real User Monitoring with Node.js

97381109baea93594baa2785dc0c99af?s=47 Rafael Verger
September 25, 2014

UMRUM - Open Source Real User Monitoring with Node.js

Apresentação feita na SEMCOMP 2014 sobre um serviço Open Source para rastreamento de usuários em tempo real. Como construímos o UMRUM usando Node.js e Redis :)

97381109baea93594baa2785dc0c99af?s=128

Rafael Verger

September 25, 2014
Tweet

Transcript

  1. UMRUM An open source real user monitoring service with Node.js

  2. @helielson @rafaelverger Quem somos? @rictorres @willmendesneto

  3. Alguém não sabe o que é Node.js? visit: speakerdeck.com/rafaelverger/nodejs-why Antes

    de mais nada...
  4. E o que é o UMRUM?

  5. Já ouviram falar desse cara?

  6. Google Analytics Realtime

  7. O UMRUM é outro RUM! Em Node.js e Open Source

    :D
  8. Tá, e U.M.R.U.M. significa o que?

  9. Em uma de nossas reuniões... e o nome?

  10. O serviço vai ser algo mágico.. plug'n'play!

  11. Tem que ser algo como: o último RUM que você

    vai precisar! O serviço vai ser algo mágico.. plug'n'play!
  12. Tem que ser um nome fucking awesome! Tem que ser

    algo como: o último RUM que você vai precisar! O serviço vai ser algo mágico.. plug'n'play!
  13. Ultimate Fucking Magic RUM!

  14. Ultimate Fucking Magic RUM!

  15. Finalmente: Ultimate Magical Real User Monitoring

  16. E por que mais um RUM?

  17. Queríamos aprender!

  18. Hackathon internacional de Node.js, desde 2009; Surgiu junto com o

    Node pra incentivar seu uso;
  19. None
  20. Então, vamos fazer um projeto, já temos um prazo, e

    o que vamos fazer? @helielson: "sempre quis implementar 'um Chartbeat'". Vamos fazer um "Chartbeat Open Source"! E por que mais um RUM?
  21. None
  22. Nosso benchmark

  23. Como rastreamos os usuários?

  24. Tracking code !function(k,w,d,s){ w._mrm=w._mrm||{}, w._mrm.hostId=k, s=c.createElement("script"), s.async=1, s.src="//umrum.io/dist/umrum-client.js", d.body.appendChild(s); }("UMRUM_KEY",window,document);

  25. Definindo um UUID pro usuário props.uid = generate_uuid(); doc.cookie =

    [ cookieName, '=', props.uid, ';expires=', weekAhead ].join(''); // UUID = xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
  26. Ei, servidor, to aqui! API.ping = function(){ if ( IS_USER_ACTIVE

    ) this.send('/ping'); this.ping_timeout = setTimeout(function(){ API.ping(); }, 30 * 1000); }
  27. API.send send = function(route){ this.element.src = [ // this.element =

    <img> this.API_URL, route, "?uid=", props.uid, "&hostId=", props.hostId, "&url=", win.location, "&title=", doct.title, "&servertime=", svtime, "&pageload=", pgload, "&t=", (+new Date) ].join(''); }
  28. Navigation Timing window.performance.timing { "loadEventStart": 1411631886735, "domComplete": 1411631886735, "responseEnd": 1411631885549,

    "responseStart": 1411631885347, "requestStart": 1411631884630, "redirectEnd": 0, "redirectStart": 0, "unloadEventStart": 0, } https://developer.mozilla.org/en-US/docs/Navigation_timing
  29. function activate_user() { USER_ACTIVE = true; } addEvent(window, 'scroll', activate_user);

    addEvent(doc.body, 'click', activate_user); addEvent(doc.body, 'mouseover', activate_user); activate_user(); Usuários ativos
  30. Usuários inativos :( _oldblur = window.onblur; window.onblur = function(){ try{_oldblur();}

    catch(e){} USER_ACTIVE = false; }; addEvent(win, 'beforeunload', API.exit);
  31. Como salvamos os dados?

  32. Como salvamos os dados?

  33. Salvando usuários ativos multi = redisclient.multi(); // pipeline multi.hincrby(user.hostId, 'curr_visits',

    1); multi.zincrby(toppagesKey, 1, user.url); multi.lpush(servertimeKey, user.servertime); multi.lpush(pageloadKey, user.pageload); multi.hmset(user.uid, user); multi.setex(EXP_PREFIX+user.uid, USR_TIMEOUT, 1); multi.exec();
  34. IMPORTANTE - Pipeline! multi = redisclient.multi(); ... multi.exec();

  35. Atualizando usuários multi.zincrby(toppagesKey, -1, old_user.url); multi.zincrby(toppagesKey, 1, user.url); multi.hmset(user.uid, user);

    multi.setex(EXP_PREFIX+user.uid, USR_TIMEOUT, 1);
  36. Removendo usuários :( multi.del(user.uid); multi.hincrby(user.hostId, 'curr_visits', -1); multi.zincrby(toppagesKey, -1, user.url);

  37. Entregando os dados multi = redisclient.multi(); // pipeline multi.hget(hostId, 'curr_visits');

    multi.zrevrangebyscore( toppagesKey, +inf', -inf', 'WITHSCORES', 'LIMIT', 0, MAX_TOPPAGES); multi.lrange(servertimeKey, 0, MAX_PERF_LIST); multi.lrange(pageloadKey, 0, MAX_PERF_LIST); multi.exec(send_data_to_dashboard);
  38. Como organizar CSS? E o Javascript? HTML com herança? Client-side

  39. HTML <button> </button> JS $('button').on('click', function() { do_something(); }) Começamos

    sem componentizar
  40. emberjs.com

  41. Posso ter componentes? Existe herança?

  42. Posso ter componentes? Existe herança? O Ember é Perfeito!!

  43. None
  44. None
  45. None
  46. {{ }}

  47. <h1>{{ page_title }}</h1>

  48. <script type="text/x-handlebars" data-template-name="components/tracked-sites" > {{"{{ site.host }}"}} </script>

  49. None
  50. facebook.github.io/react/

  51. facebook.github.io/react/ Não é um Framework!!!

  52. None
  53. var TrackedSites = React.createClass({ trackNewSite: function(host) { // ... },

    render: function() { var siteItems = this.state.sites.map(function(site) { return ( <SiteItem host={site.host} code={site.code} /> ); }); return ( <div className="site-list-panel"> <h3>Your sites</h3> <div className="site-list"> {siteItems} </div> <AddSiteForm onSiteSubmit={this.trackNewSite} /> </div> ); } }); components/tracked-sites.jsx
  54. None
  55. umrum.io