Perl scripts send log messages to Twitter

Twittering for Geeks


The Twitter service can be a platform for meaningless chatter, or you can automate access with an API and use it in ways Twitter never envisioned.

By Michael Schilli

James Thew, 123RF

Why on earth would anybody want to use a mobile phone to let the world know they are eating a pizza with friends, are down at the gym, or have just arrived somewhere by airplane?

Microblogging, as supported by Twitter or the free identi.ca variant, has some really amazing side effects. If you want to find out what the hottest issues are for humankind right at this moment, neither Google's search engine nor Wikipedia are likely to help. Take a look at the Twitter service front page (Figure 1) and you'll see people tweeting about local political upheavals, natural phenomena, the latest movie, or sports events - often long before the daily paper's editorial team or the TV channels have even noticed something is going on.

Figure 1: Why on earth do we need Twitter? The welcome page for the popular Internet service shows what people talk about.

Fragile Giant

The fact that Twitter works at all is something close to a miracle. The service offers just minimal functionality, and its infrastructure is so fragile that breakdowns are just part of the daily grind. Yet 6 million users untiringly keep feeding the fragile beast news, continuously infuse new life in the form of brand new information, and thus have kept it alive and breathing since 2006. The Twitter team is reluctant to add new functionality; in fact, this typically only occurs when faithful Twitter fans have discovered hair-raising creative workarounds to eke new functions out of the gentle giant.

Twitter doesn't really offer much: Users with an account can send text messages of up to 140 characters to the service, which then publishes them, both on the Public Time Line and under the user's account. Combine this with a mobile phone and text or web capabilities, and you have a superficial but timely style of communication.

If you are interested in what another user has to say, you can register as a Follower of that user; this is like making somebody your buddy, and it automatically routes their message stream into your own. Commonly, users follow several other users; conversely, other users follow them. Imbalance is indicative of an issue; for example, spammers tend to follow many users, but nobody follows spammers or even likes to read their messages.

Although Twitter is free now, most likely they will apply the advertising thumbscrews at some stage, just to earn some money. The free identi.ca clone looks slightly different, but it gives you exactly the same functionality, including technical details like the URL layout (Figure 2). This means that you can point the Perl Net::Twitter module, for example, away from Twitter and at identi.ca by using a single parameter to replace http://twitter.com with http://identi.ca.

Figure 2: The free compatible Twitter clone, identi.ca.

Just the Basics

Twitter's reluctance to introduce new features leads to people misusing the 140 characters available for each message as a kind of programming language to test new functions. "Retweets" - that is, messages that are worthy of being quoted and which followers of one Twitterer forward to their own followers - are one example of this. Because the original Twitter did not have this functionality, some clever users repeatedly added the RT @username string to their messages until Twitter finally gave way and recognized the "standard."

Twitter only gives you rough building blocks, and this is reflected in the lean API. All the more amazing, O'Reilly published a 400-page tome on the subject [2] describing the programming interface, including a short tutorial on web programming, and introducing a whole bunch of successful third-party Twitter applications.

Wiped Out

Although you could use the API to code another client with a GUI or text-based interface, it's also useful for cleaning up Twitter errors. When I created the perlsnapshot test account, I must have pressed the wrong button, because all of a sudden, no fewer than 20 friends appeared, and interestingly I'd never heard of any of them before. Deleting them individually in my browser would have been a nightmare, but presto, I knocked out the script shown in Listing 1 in less than five minutes, and running it against the list of false friends wiped them out of my life forever.

Listing 1: unfollow-all
01 #!/usr/bin/perl -w
02 use strict;
03 use Net::Twitter;
04
05 my $nt = Net::Twitter->new(
06   traits => [qw/API::REST/],
07   ssl    => 1,
08   username => "perlsnapshot",
09   password => "*******",
10 );
11
12 my $friends =
13   $nt->following();
14
15 for my $friend (@$friends) {
16   print
17    "$friend->{screen_name}",
18    "\n";
19   $nt->destroy_friend(
20     $friend);
21 }

My Password's Gone!

If you are conscious of security, you've probably noticed that the code includes the password needed by the script to sign on to the Twitter service. The ssl option avoids sending the password in the clear; instead, the Perl Net::Twitter module communicates with Twitter's HTTPS URLs. But with applications popping out of the ground like mushrooms, the question is: How you can avoid disclosing your password to third parties? Imagine if just one weak link in the chain were to reveal your password - time to panic.

A recent addition by Twitter, OAuth, solves this problem. This open protocol gives various applications privileges for a user account. Instead of forwarding your username and password to various providers and hoping that nobody exploits your generosity, OAuth assigns every application a unique token. The token can be revoked at any time without affecting other providers who are using separate tokens.

The Perl Net::Twitter module supports OAuth; however, Twitter insists that you register the application [3] before it gives you the Token Consumer Key and Consumer Secret. That's the theory, anyway, if the service is working - which it was not when I was writing this article.

Logging with Twitter

Listing 2 demonstrates another application for the Twitter API: a Perl module that you can embed in other Perl processes to send messages to Twitter - the twit() function. In typical Perl fashion, the function accepts either a message in the form of a string or a reference to a hash with a message field. A second parameter, home, points to the user's home directory, just in case the root user is running the program (e.g., from a backup script). Twitsend.pm hopes to find a YAML configuration file in the home directory named .twitsend that contains the password for the Twitter account. In this way, the password is in just one place and not in multiple scripts.

Listing 2: TwitSend.pm
01 package TwitSend;
02 use strict;
03 use Net::Twitter;
04 use YAML qw(LoadFile);
05 use base qw(Exporter);
06 our @EXPORT_OK = qw(twit);
07
08 #############################
09 sub twit {
10 #############################
11   my ($message) = @_;
12
13   my $opts = {};
14
15   if (
16     ref($message) eq "HASH" )
17   {
18     $opts = $message;
19     $message =
20       $opts->{message};
21   }
22
23   if ( !defined $message ) {
24     die "No message given!";
25   }
26
27   if (
28     length $message > 140 )
29   {
30     die "Message needs to ",
31         "be < 140 chars";
32   }
33
34   my $home = $opts->{home};
35
36   ($home) = glob "~"
37     unless defined $home;
38
39   my $yaml = LoadFile(
40     "$home/.twitsend");
41
42   my $nt = Net::Twitter->new(
43     traits =>
44       [qw/API::REST/],
45     ssl => 1,
46       # identica => 1,
47     username =>
48       "perlsnapshot",
49     password =>
50       $yaml->{password},
51   );
52
53   $nt->update($message);
54 }
55
56 1;

On My Balcony

My Perl-controlled irrigation system [4] has provided an invaluable and reliable service to the plants on my balcony for more than two years now. However, I do like to keep an eye on what it's doing while I'm away, so why not Twitter the pump activity so that I can check it from any Internet cafe or via my mobile phone?

After just five minutes, I was able to interface the TwitSend.pm module with the water script for the plant irrigation apparatus I described previously [4]. Then I called the twit() function with a message string and the path to a directory containing a YAML file with the account password for the perlsnapshot Twitter account.

The implementation is shown in the twitsend sample script (Listing 3), which posts the results to Twitter, as shown in Figure 3. The irrigation duration for the plants on a warm day in August took 60 seconds, and the backup on my development system completed at 11:49am. For the latest updates, feel free to check twitter.com/perlsnapshot.

Figure 3: Using Twitter as a logfile to monitor a server.
Listing 3: twitsend
01 #!/usr/bin/perl -w
02 use strict;
03 use MyTwitSend qw(twit);
04
05 twit({
06   message => "This is yet another test message.",
07   home    => "/home/mike",
08 });

This approach is similar to that used recently by my fellow columnist, Charly Kühnast, with the ttytter client [5]. Today's script only needs a .twitsend YAML file in the home directory (e.g., /home/mike), with permissions of 0500, to ensure that the file is only readable and writable by the account owner. It contains a single password:    line, which defines the Twitter password (Figure 4).

Figure 4: The TwitSend.pm configuration file, .twitsend, which sets the user password for the Twitter account.

If you feel like using the free service on identi.ca instead, uncomment the identica directive in line 46 of the TwitSend.pm module. This directive points scripts to the free identi.ca clone rather than Twitter.

Also note that Twitter will silently ignore identical messages. A cron job that sends out a "Backup finished" message every day will not do the trick, but adding a timestamp will.

If other processes tweet on separate service accounts, you can then use your personal account to follow all or some of them. When you get back from vacation, all it takes is an unfollow on the Twitter website to unhitch the log from the message stream supplied by your friends.

The API, which is accessible via Net::Twitter, also lets you delete tweets; perform administrative functions such as follow(), unfollow(), or block(); send private messages; tap into the public message stream; and do many other things. Twitter restricts access to 100 access attempts per hour and monitors both IPs and accounts.

Installation

Unfortunately, Net::Twitter and the long list of dependent modules from CPAN are not available as Ubuntu packages. However, calling a CPAN shell (perl -MCPAN -eshell) will let you install the required dependent modules by typing install Net::Twitter. Because Net::Twitter also loads Moose and supports OAuth, your mileage may vary, and a coffee break is recommended.

INFO
[1] Listings for this article: ftp://www.linux-magazin.de/pub/listings/magazin/2009/10/Perl
[2] Makice, Kevin. Twitter API: Up and Running: Learning How to Build Applications with the Twitter API. O'Reilly, 2009
[3] Twitter OAuth Application Registration: http://twitter.com/oauth_clients
[4] "Don't Blame the Gardener!" by Michael Schilli, Linux Pro Magazine, April 2007, http://w3.linux-magazine.com/issue/77/Perl_Linux-based_Gardening.pdf
[5] "Twittering Machine" by Charly Kühnast, Linux Pro Magazine, August 2009, pg. 59