Skip to content

Instantly share code, notes, and snippets.

@becckitt
Last active September 22, 2017 13:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save becckitt/120e239b0f2a53df34eece106b4ba5fd to your computer and use it in GitHub Desktop.
Save becckitt/120e239b0f2a53df34eece106b4ba5fd to your computer and use it in GitHub Desktop.
Where do metrics go?

When a tracker is added on the front end of Hymnal:

The tracker tab in Hymnal

  • A metric starts its journey being added on the frontend, in Hymnal, as an impression tracker (in the tracker sidepanel, views/hymnal_ads/_sidebar_tracking.html.erb). You can add as many trackers as you want per ad.
    • Separately, a clickthrough url is added in the Click-through url field, and notably, there is only one of these per ad.
    • Potential opportunity to simplify: In the refactor, we'll need to update how clickthrough urls are handled, since currently they're handled by metrics_instrumentation. However, since there's only one per ad, it makes more sense to make this a column on HymnalAd.
    • We'll also need to update the rake task I wrote to migrate the current clickthrough_urls over to HymnalAds, from MetricsInstrumentation
  • From there, the tracker form is submitted, and for every tracker that was added, a new tracker object is created/saved in the db (after a check to make sure the url entered is a valid url). There is a MetricsInstrumentation instance (this is also the only ever one that exists) that exists for BasicTracking trackers. Because BasicTracking urls are the only type of trackers we ever have, each new tracker gets assigned to this first instance of MetricsInstrumentation and assigned the type of BasicTracking.
  • Once that's done, it just kinda sits and waits around, until the ad is compiled, through compilers/ad.rb

When an ad is compiled:

  • An ad is compiled when an ad is published. In ad_publisher.rb, the process begins with a call to Compilers::Ad.new(ad). This sends the ad to compilers/ad.rb.

  • An ad is compiled in compilers/ad.rb. As a tldr; from here, all of the ad's options and files get compiled into a js file, and placed into compilers/ad/ad.js.erb. Learn more here.

  • When an ad compiler is initiated, the ad is then sent to either the Vox ad compiler gem (referred to as Vox::AdCompiler), or HymnalCompiler (this depends on which type of ad they are, for more info, go to compilers/ad.rb#use_vox_compiler_gem?).

  • If an ad is being compiled with Vox ad compiler gem, then it goes to this file, which sets config.manifest_path to config/adcompiler-manifest, which has a file that defines a lot of file paths.

    • If use_vox_compiler_gem? is true, the method map_ad_to_ad_compile_context is called. Within this method, ad.metrics_instrumentations an array of all the enabled metrics_instrumentations, which it then iterates through and calls metrics' complete_js method, found in models/metrics_instrumentation.rb, for each metric.
      • Potential opportunity to simplify: Within this file, it appears there's a class method in the form of a defined scope being added to select just the metrics with a type of basic_tracking, but.... this does not appear to be used anywhere.
      • Separate note: the original purpose of metrics was to allow multiple types of metrics to be created, but the only one that ever came to fruition was basic_tracking. This is where basic_tracking.rb and basic_tracking/setup.js.erb come in.
    • The complete_js method then sends a call to read the template metrics_instrumentation.js.erb
      • Potential opportunity to simplify: I honestly don't know if we need to carry this whole step over... this file is setting up three things, engagement_js, setup_js, and ad_properties, but the first two we're planning on getting rid of completely because they haven't been used in awhile. Also, I'd like to see if there's a better way to deal with ad_properties/check if maybe that isn't needed anymore either. Wondering if instead of using a js.erb template, we just use .to_json on the object and use that.
    • That template creates a new js instance of Hymnal.MetricsInstrumentation, and assembles an js object with all the metrics instrumentation info for the ad, so that all that info is ready to be inserted into the ad.
    • Inside this template, there are checks to see if setup_js is present (and if so, adds it), and does the same check for engagement_js. Setup reads this template, at metrics_instrumentation/basic_tracking/setup.js.erb, which calls addTrackerImage, and this is where the real meat of metrics is!!
      • The function addTrackerImage is defined here. This function sets up the actual tracking pixel and adds it to the body of the page.
      • Potential opportunity to simplify: both setup and engagement call for a template result of a template with their name, but engagement does not have a corresponding template. Also, it does appear that engagement does nothing, because the engagement_js method in metrics_instrumentation/basic_tracking.rb has a comment that says 'basic tracking doesn't do anything on engagement events. Override and return nothing. so.
      • Lingering questions I have: What are setup and engagement js, are they being used, and is this behavior we want to carry over with us to the new model? Feels like maybe we could flatten out a step here.
    • Also within metrics_instrumentation.js.erb, ad_properties gets called, which takes you to two places: one is in the MetricsInstrumentation model, which creates/returns a blank hash for ad_properties; and second, to BasicTracking's ad_properties method, which also creates a blank hash, adds the click_through_url, and then returns the hash.
      • Potential opportunity to simplify: uh is ad_properties getting used or can we maybe flatten out a step here too
  • On the other hand, compilers/hymnal_compiler.rb has a lot more to it.

    • Within HymnalCompiler's build method, config[:metrics_instrumentation] is set. First, it checks that metrics are enabled with @use_metrics (this is according to the metrics boolean passed in to the options hash when the compiler is initialized, and the default is true. We also decided this might be obsolete, since we are checking a lot to see if metrics are enabled, but, it doesn't really ever seem like they're disabled.) If they are (they almost always are) it sets config[:metrics_instrumentation] to the ad's corresponding metrics_instrumentations.
    • At the end of the build method, a call is made (through erb_template) to read the template ad.js.erb.
    • Within ad.js.erb, each metrics_instrumentation is iterated through, and for each metric, there's a function call to the ad's addMetricsInstrumentation function, and the metric's complete_js is passed in as an argument.
    • The function addMetricsInstrumentation is defined here, in sdk/js/ad.js. This function takes an instrumentation, adds it to the current ad's metrics_instrumentations (which is an array), and then calls the instrumentation's setAd function, which can be found here in sdk/js/metrics.js.
      • Potential opportunity to simplify: Instead of iterating through all of the trackers in ad.js.erb, then using addMetricsInstrumentation to add them to an array of all trackers, what if we did something like, set ad.trackers to an object with all of its trackers and events.

When an ad is published

  • First off, a Hymnal Ad is published, when an ad is created in the Hymnal UI and the user pushes the 'Publish' button.
  • This button calls ad_publish_path, which redirects you to PublishesController#create
  • The create method in PublishesController sets a Resque task, called PublishCreativeTask, which you can find here.
  • This task creates a new instance of AdPublisher, and calls its publish method.
  • Quick note, inside this method is also where the ad begins the compile process, here
  • Within the publish method, a new object called published_ad is created, which calls its create_published_ad method.
  • Inside create_published_ad, a new instance of PublishedAd is created.
  • The metrics_instrumentations are added in the form of metrics_configurations, which is the ad's metrics_configurations, run through their to_hash method, which formates them appropriately.
  • When a PublishedAd is created, these metrics_configurations are serialized into an array.
  • If all this goes well and nothing fails, the ad is published.

There is also something going on here that I haven't fully worked out but here are my initial notes:

  • Well, when you click that lil 'Publish' button on an ad, create a new published_ad object that stores the current state of the ad. I guess the point of this is so that you can go back and look at previous published versions, which is useful if your current version has started a fire the previous version didn't have, I think is what is happening here.
  • The published_ad is created as a published_version on a HymnalAd, of which it has_many, which you can confirm for yourself here.
  • When a new published_version of a HymnalAd is created, it checks the current metrics_configuration, which if you look here you'll note is actually just the metrics_instrumentations, but renamed to metrics_configurations. This is kind of an outdated thing, and from what I understand, they were originally renamed because they used to have more complicated things happening to them, but now they're just an array.
    • Potential opportunity to simplify Get rid of this, since metrics_configurations and metrics_instrumentations are essentially the same thing now.
  • Back in PublishedAd, you will see, starting here that there are a lot of various checks on metrics_configurations to make sure they are current, if they've changed, and if they're secure.

But how in god's name is the clickthrough url added?

Hoo boy. It took me years hours to track this down, but it turns out, a clickthrough url is added to an ad through the metric's configuration in metrics_instrumentation.js.erb. Specifically, the clickthrough url is added to the Metric through its ad_properties (to be extremely specific, I'm glazing over a step here, ad_properties calls on the basic_tracking template to actually fill in the clickthrough url). From there, when the ad is being assembled in ad.js.erb, it cycles through all its metricsInstrumentations and calls ad.js's addMetricsInstrumentation function for each. This function calls the metric's setAd function, which goes a. adds the actual ad to the metric, and b. adds each property in the metric's configuration as a property directly on the ad itself. So this is where the clickthrough_url is added to the ad.

Types of trackers we plan on supporting:

Key parts of an impression tracker:

  • Added as a pixel
  • Has a tracking pixel url
  • Added to the page on load
  • Should fire when the ad loads

Key parts of video trackers:

  • Added as a pixel
  • Has a tracking pixel url
  • Should fire when a certain event is reached, ie. Video is 25% completed
@gesteves
Copy link

gesteves commented Aug 1, 2017

Separately, a clickthrough url is added, and notably, there is only one of these per ad.

Where are clickthrough ads added?

@banderson623
Copy link

on simplifying...

This whole thing can be ripped out!

@banderson623
Copy link

I really like this idea Guille and Becca, lets make the click through part of the HymnalAd.

@andrew-a-dev
Copy link

👏 I definitely can't add any comments of things that might be wrong or missing, since I now know 💯 times more about metrics' incredible journey than I did this morning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment