Build Monitoring Widgets with Ruby and BitBar

Share this article

BitBar-small

Ruby developers are used to finding incredibly useful open source projects packaged as gems. In this tutorial, we’ll take a look at BitBar, an open source project that isn’t built in Ruby, but when combined with a small bit of Ruby can be incredibly powerful.

While the original project is no longer actively maintained, an updated fork of the project can be found here: https://github.com/kamenevn/bitbar

BitBar provides Mac OS X users an easy way to create a menu bar item from the standard output of a script. I’ll show you how to create a simple site ping monitor, and then we’ll create a Twitter follower counter.

Installing BitBar

To install BitBar, visit the GitHub repository at https://github.com/kamenevn/bitbar. Download the zip file (the button to download is in the righthand sidebar). Inside the archived folder, you will find a “Releases” folder, which holds the BitBar.app file. Put this in your Applications directory. Opening this application launches BitBar.

How BitBar Works: File Structure

BitBar is a simple application that runs all shell scripts in a given directory on an interval that is determined by the filename. Of course, you should be very careful when adding scripts to BitBar, especially if you are adding a low interval time.

To run a given file every 5 minutes, the naming structure would look something like this:

my_script.5m.sh

Of course, you will also want to make your scripts executable. Note that BitBar refers to these scripts as “plugins” in their documentation.

How BitBar Works: Script Output

In order to add visible text to your BitBar plugin, you will need to send output to STDOUT. In Ruby, this is simply the output of puts. By default, BitBar will cycle through each line of the output, unless you output the specific string “—“; anything after this line will show up in a dropdown after you click the BitBar item in the menu bar.

BitBar also allows changing the text color and responding to clicks. Clicks can either open a URL or trigger another shell script, and can be set to do so in the background.

Here’s a simple Ruby script that would create a link to StackOverflow in BitBar:

url = "https://stackoverflow.com"
puts "Go to StackOverflow | href=#{url}"

Notice the | separating the outputted text and the parameters for clicking. The href parameter tells BitBar to open this URL when clicked. Here’s a more complex example, showing some red text that triggers another executable script:

puts "Run My Script | color=#ff0000 bash=/path/to/your/script.sh"

Of course, once again, you’ll want that script to be set to be executable using chmod.

Finally, if the script takes parameters, you can add them using param1, param2, and param3. If you would like to execute the bash script in the background on click, set the parameter terminal= to false. For example, you might want to use the current time as a parameter for a script that runs in the background:

current_time = Time.now.to_i
puts "Run My Script | color=#ff0000 bash=/path/to/your/background_script.sh terminal=false param1=#{current_time}"

Creating a Site Monitor

Now that we know how BitBar works, let’s create a site monitor in Ruby that we can then use with BitBar. As a disclaimer, you should know that only checking a site’s status from your own computer may not give you the full picture. To really know if your sites are down, use monitoring services and sites like uptimerobot.com. But this little widget will provide a quick glance and signal potential problems as they occur.

The required behavior is a bullet point that is red or green, depending on the status of a list of sites. I want to be able to keep that list of sites in an easy-to-update YAML file. When one of the sites goes down, I want to be able to click the bullet point in my menu bar and see the failing site. I also want to be able to click that menu item to visit the site in my browser.

Let’s get started with some Ruby!

The Site Checker Class

First, we’ll create a simple class called SiteChecker:

# /path/to/bitbar_plugins/site_checker/site_checker.rb
require 'yaml'
require 'net/http'

class SiteChecker

  def initialize(sites)
    @sites = sites
  end

  def up?(server, port=80)
    http = Net::HTTP.start(server, port, {open_timeout: 5, read_timeout: 5})
    response = http.head("/")
    response.code == "200"
  rescue Timeout::Error, SocketError
    false
  end

  def run
    results = {}
    @sites.map {|s| results[s] = up?(s) }
    results
  end
end

Great! Now we have a simple Ruby class that can check any given site, can be initialized with a list of sites to check, and returns a hash of results.

Next, let’s write the actual BitBar plugin that will use the SiteChecker class. Add a folder to the BitBar plugins folder called site_checker and save the site_checker.rb file there. Next, create a file called site_checker.3m.sh, and place it in the BitBar plugins directory. Here’s what that file looks like:

#!/usr/bin/env ruby
# Note: the ruby path above should point to your Ruby installation.
# You can verify this by checking `which ruby`
$:.unshift File.dirname(__FILE__)
require 'site_checker/site_checker.rb'
require 'yaml'
def run
  sites = YAML.load_file(File.join(__dir__, 'site_checker/sites.yml'))["sites"]
  site_checker = SiteChecker.new(sites)
  results = site_checker.run
  if results.values.include? false
    puts "• | color=#ff0000"
    puts "---"
    results.select {|key, val| val == false }.keys.each do |site|
      puts "#{site} down | href=http://#{site}"
    end
  else
    puts "• | color=#82B021"
  end
end
run

This simple script formats the output of our SiteChecker class for BitBar to use. Finally, we need to make sure we’ve added our sites.yml file inside our site_checker directory:

sites:
  - "google.com"
  - "twitter.com"
  - "yoursite.com"

Make sure your site uses only its domain name (without any protocols).

The final step is to make the script executable. You can do this by running chmod +x site_checker.3m.sh. The resulting file structure should look like this:

├── site_checker
│   ├── site_checker.rb
│   └── sites.yml
├── site_checker.3m.sh

Twitter Follower Count

Next, let’s do something a bit more involved. We’ll show how many users we are following and how many users are following us on Twitter.

The first step is to register an application with Twitter. Once you’ve followed the steps and successfully created your project, you will need to locate the API keys and access tokens for the application.

Next, create a folder inside your BitBar plugins directory called twitter_counter, and an associated plugin file called twitter_counter.10m.sh.

Inside of the newly created twitter_counter folder, create an account_detail.rb file. We will use this to create a simple class that will return follow count information for a Twitter account.

The AccountDetail class looks like this:

require 'twitter'
class AccountDetail
  attr_accessor :user

  def initialize(username)
    @client = create_client
    @user = @client.user(username)
  end

  def followers
    user.followers_count
  end
  def followings
    user.friends_count
  end

private

  def create_client
    Twitter::REST::Client.new do |config|
      config.consumer_key        = "YOUR CONSUMER KEY"
      config.consumer_secret     = "YOUR CONSUMER SECRET"
      config.access_token        = "YOUR ACCESS TOKEN"
      config.access_token_secret = "YOUR ACCESS TOKEN SECRET"
    end
  end
end

Make sure you run gem install twitter if you have not already. In the previous example, we used built-in libraries. Twitter is a third-party gem that must be installed before this class will work.

The AccountDetail class essentially wraps a very small subsection of the Twitter gem for our use case. Next, edit the twitter_counter.10m.sh file to look like this:

#!/usr/bin/env

$:.unshift File.dirname(__FILE__)
require 'twitter_counter/account_detail'

def run
  @account_detail = AccountDetail.new('your_twitter_name')
  puts "#{@account_detail.followers} followers"
  puts "#{@account_detail.followings} following"
end
run

Finally, edit the permissions on the script to make it executable. As long as everything is set up correctly, you should see a simple widget in the menu that cycles between your “follower” count and your “following” count. Of course, we could use much more of the Twitter API to do even more interesting things!

Conclusion

While this tool may not be used in a project you are intending to ship to your clients, it certainly can be a useful and fun tool to create your own native applications. Here are some ideas for more projects using BitBar:

  • Build status indicator (integrating with something like CircleCI or Codeship)
  • Stripe sales ticker
  • A simple easy-to-access action list for performing common scriptable tasks or macro-functions
  • Visual graphing of things with something like (Spark)[https://github.com/holman/spark]

Share your ideas with us here! Happy hacking!

Jonathan CutrellJonathan Cutrell
View Author

Jonathan lives in Chattanooga, Tennessee and is the Director of Technology at Whiteboard and host of Developer Tea, a top-ranked podcast for developers that is published 4 times per week. He also manages to write and publish online weekly, and still have time to feed his dog and date his wife, Lauren.

GlennG
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week