30 - May - 2013

Dashing - An open source Dashboard

Post by Chris H

Shopify open sourced Dashing late last year, their Dashboard software created for displaying dashboards on TVs around their office. We decided to see have a play and see what statistics we could show on our office TVs. Install is simple via gem, although as a non Ruby person I spent more time than I should have installing Ruby 1.9 (from source in the end). Once up the server runs on a port (3030 as standard) and applications can simply send data to the dashboard in a certain format and it is displayed immediately.

Open Atrium

We currently use Open Atrium, a Drupal based package for our intranet & support ticketing system. We decided to expose to the dashboard emergency and high priority tickets, plus a count of those unassigned in the queue and approaching our response SLA time. The dashboard also lists the top users who have tickets assigned to them to highlight any possible bottlenecks, in the future this could easily be expanded to show other stats like 'top ticket slayers today' etc. Extracting the statistics from Open Atrium uses a mixture of hand crafted SQL code and programatically calling custom Views displays. As Atrium uses a somewhat complex mix of Organic Groups & Spaces to control access to nodes we cheat and switch to User ID 1 to bypass all the usual Drupal access control.

function casetracker_stats_ticket_counts() {
  $counter = new stdClass;
  // Switch user to UID 1 to execute View queries with no access control limits
  global $user;

  $account = $user;
  $user = user_load(1);

  $counts = views_get_view_result('atrium_emergency', 'block_1');
  $counter->high = $counts[0]->num_records ? $counts[0]->num_records : 0;
  $counter->normal = $counts[1]->num_records ? $counts[1]->num_records : 0;
  $counter->low = $counts[2]->num_records ? $counts[2]->num_records : 0;
  $counter->emergency = $counts[3]->num_records ? $counts[3]->num_records : 0;
  $counts = views_get_view_result('atrium_emergency', 'attachment_1');
  $counter->sla = $counts[0]->num_records ? $counts[0]->num_records : 0;
  $counts = views_get_view_result('atrium_emergency', 'attachment_2');
  $counter->unassigned = $counts[0]->num_records ? $counts[0]->num_records : 0;
  $counts = views_get_view_result('atrium_emergency', 'attachment_3');
  $counter->security = $counts[0]->num_records ? $counts[0]->num_records : 0;

  // Reset user back to default
  $user = $account;
  return $counter;

Dashing Widgets can exist on multiple dashboards, but keeping them all up to date requires a single HTTP POST call with the widget name in the URI. The data payload is a simple JSON structure which is different depending on the type of Dashing widget. We push the data every 15 minutes which is triggered by the standard Drupal cron run and implementing the hook_cron() function in our stats module.

/* * Send a data set to a specified widget on a Dashing board */ function casetracker_stats_dashing_widget_push($widgetid, $data) { $endpoint = variable_get('casetracker_stats_dashing_endpoint', ''); $url = $endpoint . '/widgets/' . $widgetid; drupal_http_request($url, array(), 'POST', '{ "auth_token": "' . variable_get('casetracker_stats_dashing_token', '') . '", ' . $data . '}'); } /* * Update Dashing board widgets with latest data */ function casetracker_stats_dashing() { $endpoint = variable_get('casetracker_stats_dashing_endpoint', ''); if ($endpoint) { $counts = casetracker_stats_ticket_counts(); watchdog('stats', print_r($counts, true), array(), WATCHDOG_DEBUG); casetracker_stats_dashing_widget_push('emergency', '"value": "' . $counts->emergency . '"'); casetracker_stats_dashing_widget_push('high', '"value": "' . $counts->high . '"'); casetracker_stats_dashing_widget_push('server', '"value": "' . $counts->normal . '"'); casetracker_stats_dashing_widget_push('slabreach', '"current": "' . $counts->sla . '"'); casetracker_stats_dashing_widget_push('unassigned', '"current": "' . $counts->unassigned . '", "last": "' . variable_get('casetracker_stats_unassigned', 0). '"'); // Remember previous unassigned number and update if different if ($counts->unassigned != variable_get('casetracker_stats_unassigned', 0)) { variable_set('casetracker_stats_unassigned', $counts->unassigned); } // Staff Users $users = casetracker_stats_user_staff_tickets(); $items = array(); foreach($users as $uid => $data) { $account = new stdClass; $account->name = $data['name']; $account->uid = $uid; $items[] = array('label' => theme('username', $account), 'value' => $data['count']); } casetracker_stats_dashing_widget_push('staff-tickets', '"items": ' . json_encode($items)); } } /* * Regular job processing for case tracker stats */ function casetracker_stats_cron() { casetracker_stats_dashing(); }


Icinga is an open source monitoring system that was originally created as a fork of Nagios. We use Icinga to perform a range of checks on remote servers, such as load, diskspace or a HTTP string on a page to ensure the webserver is serving pages correctly. When various thresholds are exceeded Icinga creates warnings or critical alerts that we can then send and display in Dashing. We used Nokigiri to simply scrape the count of current alerts, such as critical alerts in the example below: count = page.css( "//*[@title='Unacknowledged Services CRITICAL']" )[0].text send_event('icinga-critical', value: count)


Dashing comes with a widget to display tweets for certain search terms, we currently just look for any @ixisit replies/mentions but this could be expanded for any hash tag, or other useful Twitter accounts like Drupal security announcements There is also another contributed widget on the additional widgets page that can parse Twitter followers / tweet counts etc.


We currently have Apple TV's already hooked up to use airplay but there still isn't a native browser yet. We opted for a Raspberry Pi that is powered directly from the TV via USB. We've then configured Raspbian to boot straight into LXDE and open Chrome fullscreen. The total cost of the Pi, wireless dongle, power & HDMI cable was less than £40!

Future statistics

Our use case currently is slightly different as we support lots of different Drupal sites, so we just want some high level totals of potential issues rather than detailed site specific statistics. Dashing does however support multiple dashboards so the possibilities are endless. It is interesting to think about what other information could be displayed on prominent dashboards like TVs around the office, especially from Drupal. There is a range of Drupal statistics from outstanding security updates, last failed logins to recent article submissions that could be really useful in a dashboard. The list of third party widgets is growing with other widgets of interest including Jenkins build progress, and in the last week alone travel time from tomtom and Pingdom. Dashing on github

Profile picture for user Chris H

Chris H


A really intersting article, thanks for sharing Chris.

Just to let you know you have a couple of spam comments on your blog. Feel free to add me your systems as a spam warrior if you want me swat these for you.

Best, Paul

Paul Booker 1st June 2013

Mollom working as well as ever on the spam comments there! Manually submitted to Mollom now.


Mike C 7th June 2013

In reply to by Paul Booker

Very interesting.

I had installed dashing and I getting hard time to find and/or created widget for specific needs.

I would be happy to get a hand on how get thing started.

Thanks !

Visitor 11th June 2013

Good write-up. I used your icinga code snippet to successfully extract nagios alerts into my dashboard also

Phil Bowers 21st June 2013

We are looking at using Atrium to manage ticketing. Did you use the D6 or D7 version of Atrium? As I understood it D6 Atrium includes ticketing management, but that isn't in D7 Atrium yet.

ShaunLaws 9th October 2013

Hi Shaun,

We've been using Atrium v1.x (Drupal 6) since before it was 1.0 release.

ixisit 25th September 2014

In reply to by ShaunLaws

Add new comment

Share this article

Our thoughts

Let's work together

Get in touch and find out how we can empower your organisation.
Back to top