As of 1.3, uWSGI includes an alarm system. This subsystem allows the developer/sysadmin to 'announce' special conditions of an app via various channels. For example, you may want to get notified via Jabber/XMPP of a full listen queue, or a harakiri condition. The alarm subsystem is based on two components: an event monitor and an event action.
An event monitor is something waiting for a specific condition (like an event on a file descriptor or a specific log message).
As soon as the condition is true an action (like sending an email) is triggered.
Event monitors can be added via plugins, the uWSGI core includes the following:
log-alarm
trigger alarm when a specific regexp matches a logline
alarm-fd
trigger alarm when the specififed file descriptor is ready (low-level, it is the base of most of the alarm plugins)
alarm-backlog
trigger alarm when the socket backlog queue is full
You can define an unlimited number of alarms. Each alarm has a unique name.
Currently the following alarm actions are available in the main distribution:
'cmd' run a command passing the log line to the stdin 'signal' generate a uwsgi signal 'mule' send the log line to a mule 'curl' pass the log line to a curl url (http,https and smtp are supported) 'xmpp' send the log line via XMPP/jabber
To define an alarm, use the option --alarm
.
--alarm "<name> <plugin>:<opts>"
Remember to quote ONLY when you are defining alarms on the command line.
[uwsgi]
alarm = mailme cmd:mail -s 'uWSGI alarm' -a 'From: [email protected]' [email protected]
alarm = cachefull signal:17
Here we define two alarms: mailme
and cachefull
. The first one invokes
the mail
binary to send the log line to a mail address; the second one
generates an uWSGI signal. We now need to add rules to trigger alarms:
[uwsgi]
alarm = mailme cmd:mail -s 'uWSGI alarm' -a 'From: [email protected]' [email protected]
alarm = cachefull signal:17
log-alarm = cachefull,mailme uWSGI listen queue of socket
log-alarm = mailme HARAKIRI ON WORKER
The syntax of log-alarm is
--log-alarm "<name> <regexp>"
In our previous example we defined two conditions using regexps applied to log lines. The first one will trigger both alarms when the listen queue is full, while the second will only invoke 'mailme' when a worker commits harakiri.
You may be right. But if you throw away your "being a cool programmer with a lot of friends and zero money" book for a moment, you will realize just how many things you can do with such a simple system. Want an example?
[uwsgi]
alarm = jabber xmpp:[email protected];mysecretpassword;[email protected],[email protected]
log-alarm = jabber ^TERRIBLE ALARM
Now in your app you only need to add
print "TERRIBLE ALARM the world exploded !!!"
to send a jabber message to [email protected]
and [email protected]
without adding any significant overhead to your app (as alarms are triggered by
one or more threads in the master process, without bothering workers).
How about another example?
Check this Rack middleware:
class UploadCheck
def initialize(app)
@app = app
end
def call(env)
if env['REQUEST_METHOD'] == 'POST' and env['PATH_INFO'] == '/upload'
puts "TERRIBLE ALARM an upload has been made"
end
@app.call(env)
end
end
Such a versatile system could be open to a lot of ugly bugs, mainly infinite loops. Thus, try to build your regexps carefully. The embedded anti-loop subsystem should protect against loglines wrongly generated by alarm plugin. This system is not perfect so please double-check your regexps.
If you are building a plugin, be sure to prepend your log messages with the
'[uwsgi-alarm' string. These lines will be skipped and directly passed to the
log subsystem. A convenience API function is available: uwsgi_log_alarm()
.
Enabling log-alarm automatically puts the uWSGI instance in :term:`log-master mode`, delegating log writes to the master. The alarm subsystem is executed by the master just before passing the log line to the log plugin. Blocking alarm plugins should run in a thread (like the curl and xmpp one), while the simple ones (like signal and cmd) may run directly in the master.
Run a shell command, logline is passed to the stdin:
cmd:<command>
Raise a [wiki:SignalFramework] uwsgi signal:
signal:[signum]
Send the logline to a mule waiting for [wiki:Mules messages]
mule:[mule_id]
Send logline to a curl url. This is not compiled in by default, so if you need to build it just run:
python uwsgiconfig.py --plugin plugins/alarm_curl
curl:<url>[;opt1=val1;opt2=val2]
url
is a standard curl url, while the options currently exposed are
"url"
"mail_to"
"mail_from"
"subject"
"ssl"
"auth_user"
"auth_pass"
"method"
"timeout"
"conn_timeout"
So, for sending mail via SMTP AUTH:
[uwsgi]
plugins = alarm_curl
alarm = test curl:smtp://mail.example.com;[email protected];[email protected];auth_user=uwsgi;auth_pass=secret;subject=alarm from uWSGI !!!
Or to POST the logline to an http server protected with basic auth:
[uwsgi]
plugins = alarm_curl
alarm = test2 curl:http://192.168.173.6:9191/argh;auth_user=topogigio;auth_pass=foobar
Probably the most funny/interesting one. You need the libgloox
package to build the xmpp alarm plugin (on Debian/Ubuntu, apt-get install gloox-dev
).
python uwsgiconfig.py --plugin plugins/alarm_xmpp
xmpp:<jid>;<password>;<recipients>
You can set multiple recipients using ',' as delimiter.
[uwsgi]
plugins = alarm_xmpp
alarm = jabber xmpp:[email protected];secret1;[email protected],[email protected]
A funnier thing still about the XMPP plugin is that you will see the Jabber account of your app going down when your app dies...
Some XMPP servers (most notably the OSX server one) requires you to bind to a resource. You can do thus by appending /resource to the JID:
[uwsgi]
plugins = alarm_xmpp
alarm = jabber xmpp:[email protected]/uWSGI;secret1;[email protected],[email protected]
A toy plugin for OSX, used mainly for showing Objective-C integration with uWSGI. It simply uses the OSX speech synthesizer to 'announce' the alarm.
python uwsgiconfig.py --plugin plugins/alarm_speech
[uwsgi]
plugins = alarm_speech
http-socket = :8080
alarm = say speech:
log-alarm = say .*
Turn on your speakers, run uWSGI and start listening...
Starting with 1.9.9 uWSGI includes the --alarm-segfault
option to raise an
alarm when uWSGI segfaults.
The airbrake
plugin can be used to send segfault backtraces to airbrake
compatible servers. Like Airbrake itself and its open source clone errbit
(https://github.com/errbit/errbit), Airbrake support is experimental and it
might not fully work in all cases.
plugins = airbrake
alarm = errbit airbrake:http://errbit.domain.com/notifier_api/v2/notices;apikey=APIKEY;subject=uWSGI segfault
alarm-segfault = errbit
Note that alarm-segfault does not require airbrake plugin. A backtrace can be sent using any other alarm plugin.