Slide 1

Slide 1 text

Jon McCartie LifeChurch.tv Dashboards w/ Dashing

Slide 2

Slide 2 text

Hi! I’m Jon and I’m a Ruby developer at

Slide 3

Slide 3 text

Open (Free Resources) Church Online Platform Church Metrics YouVersion (The Bible App) Develop.Me

Slide 4

Slide 4 text

Why Dashboards?

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

Point your browser at localhost:3030 and have fun! Install $ gem install dashing $ dashing new sweet_dashboard_project $ bundle $ dashing start

Slide 7

Slide 7 text

Data Get the data (Ruby) Listen for data (JS/CS) Display data (HTML)

Slide 8

Slide 8 text

Basics

Slide 9

Slide 9 text

Number Widget

number.html

Slide 10

Slide 10 text

Number Widget class Dashing.Number extends Dashing.Widget ready: -> # This is fired when the widget is done being rendered onData: (data) -> # Fired when you receive data # You could do something like have the widget flash each time data comes in by doing: # $(@node).fadeOut().fadeIn() # Any attribute that has the 'Dashing.AnimatedValue' will cause the number to animate when it changes. @accessor 'current', Dashing.AnimatedValue # Calculates the % difference between current & last values. @accessor 'difference', -> if @get('last') last = parseInt(@get('last')) current = parseInt(@get('current')) if last != 0 diff = Math.abs(Math.round((current - last) / last * 100)) "#{diff}%" else "" # Picks the direction of the arrow based on whether the current value is higher or lower than the last @accessor 'arrow', -> if @get('last') if parseInt(@get('current')) > parseInt(@get('last')) then 'icon-arrow-up' else 'icon-arrow-down' number.coffee

Slide 11

Slide 11 text

Get That Data SCHEDULER.every '1m', :first_in => 0 do |job| send_event('karma', { current: rand(1000) }) end sample_job.rb This job will run every minute, and will send a random number to ALL widgets that have data-id set to 'karma'.

Slide 12

Slide 12 text

JavaScript Alerts class Dashing.NewRelic extends Dashing.Widget @FAILED_JOB_ALERT_THRESHOLD: 10 onData: (data) => super if (@get('current_failed') > Dashing.Metrics.FAILED_JOB_ALERT_THRESHOLD) $(@node).addClass('status-danger') $(@node).closest('li').css('z-index',10) else $(@node).removeClass('status-danger') $(@node).closest('li').css('z-index',2) new_relic.coffee

Slide 13

Slide 13 text

Our Dashboard

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

Our Dashboard 1. Code Climate 2. Deploys 3. Desk 4. Github 5. New Relic 6. Pingdom 7. Rdio 8. Trello

Slide 16

Slide 16 text

Github require 'octokit' SCHEDULER.every '60s', :first_in => 0 do |job| client = Octokit::Client.new(:login => "login", :password => "password") %w[churchmetrics open chop develop-dot-me].each do |repo| current = client.pull_requests("lifechurch/#{repo}").size send_event("#{repo}_pull_requests", current: current) end end

Slide 17

Slide 17 text

Code Climate require 'httparty' projects = { my_project: "repo", } SCHEDULER.every ‘3m' do |job| projects.each do |name, repo| response = HTTParty.get("https://codeclimate.com/api/repos/#{repo}", body: {api_token: API_TOKEN} ) data = { current: response[:last_snapshot]["gpa"].to_s, last: (response[:previous_snapshot]["gpa"].to_s rescue "---") } send_event("codeclimate_#{name}", data ) end end

Slide 18

Slide 18 text

Deploys user_email = `git config --global user.email`.chomp() data = { message: message, at: Time.now.to_i, who: user_email } redis = Redis.new redis.sadd("#{product}_deploys", data.to_json) inside our deployment script SCHEDULER.every '10s', :first_in => 0 do |job| redis = Redis.new %w[churchmetrics open chop devdotme].each do |product| data = redis.smembers("#{product}_deploys").map {|x| JSON.parse x}.sort_by { |k| k["at"] } items = data.pop(2).reverse! items.each {|i| i["at"] = relative_time_ago(Time.at(i["at"].to_i))+" ago"} items.each {|i| i["who"] = gravatar_url(i["who"])} send_event("#{product}_deploys", items: items) end end deploys_job.rb

Slide 19

Slide 19 text

Rdio require 'rdio' SCHEDULER.every ‘20s' do |job| user_id = "blahblah" rdio = Rdio::BaseApi.new(“app_key", “app_secret") response = JSON.parse rdio.call("get", {"keys" => user_id, "extras" => "lastSongPlayed,lastSongPlayTime"}) if response["status"] == "ok" res = response["result"][user_id] song = res["lastSongPlayed"] data = { album: song["album"], artist: song["albumArtist"], cover: song["icon"], title: song["name"] } send_event("now_playing", data) end end

Slide 20

Slide 20 text

New Relic api_url = 'https://api.newrelic.com/accounts/%s/applications/%s/%s.xml' action = :threshold_values apps = [] SCHEDULER.every ‘30s' do |job| global_metrics = [] apps.each do |app| metrics = {} url = api_url % [app[:account_id], app[:app_id], action] data = { headers: { "x-api-key" => app[:api_key]} } response = HTTParty.post(url,data).symbolize_keys! response[:threshold_values].each do |metric| metric.symbolize_keys! slug = metric[:name].downcase.gsub(/ /,'_') metrics[slug.to_sym] = metric[:formatted_metric_value] metrics[slug.to_sym] = metrics[slug.to_sym].gsub(/[^\d\.]/,'').to_i.ceil if slug == 'response_time' metrics[slug.to_sym] = metrics[slug.to_sym].gsub(/rpm/,'') if slug == 'throughput' end send_event("#{app[:name]}_product_health", {response_time: metrics[:response_time]}) send_event("#{app[:name]}_product_status", metrics) end end

Slide 21

Slide 21 text

What Will You Make?

Slide 22

Slide 22 text

Dashing: http://dashing.io Questions: @jmccartie