|
InterMapper 5.2 has several new features that make it easier to build command-line probes. Here are some pointers, and a fun example that uses the new features to retrieve temperature data from the US NOAA weather feed in a particular city.
How does this probe work? The customer opens the probe picker, selects the Weather Service-Temp probe (it's in the Miscellaneous/Test category). Enter the city code for the closest weather station (KLEB is at Lebanon Municipal Airport, about a half mile to the south of us.) The Status window shows the name of the weather station, and there's a chartable value for the temperature reading.
Under the covers, InterMapper launches a Python program to contact the weather service, retrieve the meteorological conditions for the indicated city, and parses out the XML response to retrieve the temperature. (There's lots more information in the feed - the program could easily be extended to display more information.) Here are some of the features of this probe:
1) It's now easy to write cross-platform Python probes. The ${PYTHON} macro gives the path to the built-in python interpreter of InterMapper DataCenter no matter what platform you're using. For example, the probe can now use:
cmd = "${PYTHON} program.py"
and InterMapper will invoke Python by substituting the proper path, whether on Windows, OSX, or Linux.
NB The InterMapper DataCenter (IMDC) must be installed. This happens automatically with InterMapper 5.2 on Windows and OSX; Linux and Unix systems require a separate install for IMDC.
2) Probe writers can now include the script directly in the text of the probe file. (Earlier versions of InterMapper required that the script be saved separately in the Tools directory or elsewhere.) This makes it much easier to write scripts and keep the probe file in sync. To do this, use the new <tool:program-name> section in your probe file. The example file contains a program named noaa-weather.py.
When InterMapper loads the probe, it parses out this section and saves it in a folder within the Tools directory of InterMapper Settings. These programs may also save private files in that directory.
3) The example probe file uses a couple interesting Python libraries. First is urllib2 that makes it easy to retrieve data from web services. It's a few straightforward calls to build a url, issue it, and retrieve the results.
4) The probe also uses the xml.dom.minidom library to parse out XML data returned from the NOAA web service. This library is particularly well-explained in Chapter 9 of Dive into Python (see below)
References
Developer Guide: General information about building custom probes
http://download.dartware.com/docs/DevGuide52/
${PYTHON} macro:
http://download.dartware.com/docs/DevGuide52/Content/02-CustomProbes/builtinvariablereference.htm#commandlinevariables
Companion Scripts: Including the script directly into the probe file.
http://download.dartware.com/docs/DevGuide52/Content/02-CustomProbes/Companion_Scripts.htm
Python Documentation:
urllib2 - http://docs.python.org/library/urllib2.html
xml.dom.minidom - http://docs.python.org/library/xml.dom.minidom.html
Dive into Python: A very readable chapter on XML processing in Python
http://diveintopython.org/xml_processing/
The NOAA Temperature Probe
To use this probe, copy the text below, save it to a text editor, then use File->Import->Probe... in InterMapper.
<!--
Weather Service Temperature - Retrieve the temperature from the NOAA weather XML (com.dartware.tool.noaa.txt)
Copyright (c) 2009 Dartware, LLC.
Please feel free to use this as a base for further development.
-->
<header>
type = "cmd-line"
package = "com.dartware"
probe_name = "tool.noaa"
human_name = "Weather Service-Temperature"
version = "1.2"
address_type = "IP"
display_name = "Miscellaneous/Test/Weather Service-Temp"
</header>
<description>
\GB\Retrieve the current temperature\p\
This probe retrieves the current temperature from the NOAA weather feed. To see the proper city code, visit:
\u4=http://www.weather.gov/xml/current_obs/\http://www.weather.gov/xml/current_obs/\p0\
</description>
<parameters>
"Weather Station" = "KLEB"
</parameters>
<command-line>
path=""
cmd="${PYTHON} noaa-weather.py"
arg="${Weather Station}"
</command-line>
<command-exit>
-- These are the exit codes used by Nagios plugins
down: ${EXIT_CODE}=4
critical: ${EXIT_CODE}=3
alarm: ${EXIT_CODE}=2
warn: ${EXIT_CODE}=1
okay: ${EXIT_CODE}=0
</command-exit>
<command-display>
\b5\ Temperature for $loc\p0\
Temperature: $temp \3g\degrees F\p0\
</command-display>
<tool:noaa-weather.py>
# noaa-weather.py
# Scan the XML results from NOAA's XML feeds
# e.g., http://www.weather.gov/xml/current_obs/KLEB.xml
# for relevant weather-related information.
# 25 Mar 2009 -reb
import os
import re
import sys
import getopt
import urllib
import urllib2
import htmllib
from xml.dom import minidom
# httplib.HTTPConnection.debuglevel = 1 # force debugging....
# options are: station
try:
opts, args = getopt.getopt(sys.argv[1:], "")
except getopt.GetoptError, err:
searchString = "getopt error %d" % (err)
station = args[0]
userAgent = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; en-us) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.2 Safari/525.20.1"
noaaString = "http://www.weather.gov/xml/current_obs/%s.xml"
noaaString = noaaString % (urllib.quote_plus(station))
# print noaaString;
retcode = 4;
try:
request = urllib2.Request(noaaString)
opener = urllib2.build_opener()
request.add_header('User-Agent', userAgent)
usock= opener.open(request)
# print buf
except IOError, e:
if hasattr(e, 'reason'):
resp = 'We failed to reach a server. '
reason = 'Reason: ' + 'Wrong host name?' # e.reason[1]
elif hasattr(e, 'code'):
resp = 'The server couldn\'t fulfill the request. '
reason = 'Error code: '+ str(e.code)
print "\{ $temp := '%s', $loc := 'Unknown' } %s" % (0, resp + reason)
sys.exit(retcode) # make it look down
retcode = 0 # looks like it'll succeed
xmldoc = minidom.parse(usock)
tempList = xmldoc.getElementsByTagName('temp_f')
tempElem = tempList[0]
tempval = tempElem.firstChild.data
loclist = xmldoc.getElementsByTagName('location')
locval = loclist[0].firstChild.data
print "\{ $temp := '%s', $loc := '%s' }%s" % (tempval, locval, tempval + ' degrees at ' + locval)
sys.exit(retcode)
</tool:noaa-weather.py>
|