Showing posts with label sanity. Show all posts
Showing posts with label sanity. Show all posts

December 18, 2008

Day 18 - Logging Tools

Logging is good, right? There are lots of logging libraries for various languages to help you with logging events and behavior in your software.

You can log to files, log to email, log to the network, log from the network, and log to stdout, etc. As a software developer, you get to make a choice on where, how, and why you log. What if you're a systems administrator? What if the software developer chose to write everything to stdout without identifying information such as timestamps?

If the tools you are using all have configurable logging, you may not benefit from this article. If you have something without configurable logging, you're still in luck. There are a few tools out there that will help you turn output into good logging.

For this task, you have at least two options: multilog or logger.

logger

Logger is a helpful command-line interface to sending syslog messages. Since it uses syslog, you get all the beneficial configurability of syslogd.conf. The logger tool come standard on just about every unix-like OS (Linux, Solaris, FreeBSD, etc), and vary by feature. Here's an example of logger usage:
% logger "hello world"
% tail -1 /var/log/messages
Dec 17 22:20:13 snack jls: hello world
The default tag (-t flag) is $USER, or "jls" for me. Most programs use the tag for the program name and pid. If you run logger with no message, it reads messages from stdin:
% echo "hurray logging" | logger -t myprocess
% tail -1 /var/log/messages
Dec 17 22:21:58 snack myprocess: hurray logging
If you're on FreeBSD, logger can log to a remote host using logger -h <hostname>, meaning you can log to a remote host without modifying syslogd.conf, if you desire.

As a more useful example, here's how to make a cronjob log its output to syslog:

0 3 * * * rsync -av /data filer:/backups/data | logger -t "backup-data"
All of rsync's output will show up in syslog logs:
Dec 17 22:31:48 snack backup-data: sending incremental file list
Dec 17 22:31:48 snack backup-data: data/
< other output trimmed >
Configurability: You can choose where your log messages go (by file or host) with /etc/syslog.conf. Log rotation is done by using logrotate (linux) or newsyslog (freebsd), and most systems come with log rotation enabled by default.

multilog

The multilog tool is part of the daemontools suite of tools. Multilog's configuration is done completely on the command-line. With multilog, you can timestamp logs and even filter them to different logfiles. As a bonus, it supports logfile rotation.

Multilog logs to directories, not files. Each directory contains a few files: current, lock, and state. Other files that will show up here are rotated logfiles. A very simple example of multilog with timestamps follows:

% echo "Hello there" | multilog t ./log
% ls log
current  lock  state
% cat log/current
@400000004949f46513a31f5c Hello there
The wacky @4000....f5c is a timestamp in tai64n format. To convert tai64n to local, readable time, use the tai64nlocal command that comes with daemontools:
% tai64nlocal < log/current
2008-12-17 22:57:31.329457500 Hello there
The timestamps in the logs are very high precision, as you can see. And yes, tai64nlocal will convert to the correct timezone based on your environment (/etc/localtime or the TZ environment variable).

As a more complex example, we can have multilog log lines starting with 'ERROR' in them to another log directory in addition to the normal one. Here's how:

multilog t '-*' '+* ERROR*' ./errors '+*' ./log
This says to timestamp. By the way, 't' is required to be the first config option if you want timestamps. Then we use a few line selections: '-*' means deselect everything and '+* ERROR*' will select any line starting with error. This may not make sense, but the '* ' before 'ERROR' is because timestamps are added immediately, so the '*' matches the timestamp. Awkward, but it is what it is.
% alias mylog="multilog t '-*' '+* ERROR*' ./errors '+*' ./log"
% echo "Hello world" | mylog
% echo "ERROR something is wrong" | mylog
% cat errors/current
@400000004949f71c36d3a30c ERROR something is wrong
% cat log/current 
@400000004949f71c362af374 Hello world
@400000004949f71c36d3a30c ERROR something is wrong
Once you understand the configuration syntax for multilog, you can do some neat things with it as exampled above. Using multilog in the cronjob example above:
0 3 * * * rsync -av /data filer:/backups/data | multilog t /var/log/data-backups
And the output looks like this:
% head -2 /var/log/data-backups/current
@400000004949f9930274befc sending incremental file list
@400000004949f993038ece04 data/

# Let's make it readable:
% head -2 /var/log/data-backups/current | tai64nlocal
2008-12-17 23:19:37.041205500 sending incremental file list
2008-12-17 23:19:37.059690500 data/

One benefit to tai64n is that your log files are sorted simply by being prefixed with the timestamp (no sort(1) call necessary), so if you have gigs and gigs of logs, you could use binary search to very quickly find a small time range to investigate. Syslog's timestamp format does not sort properly, so you can't do this.

Logging is super useful. The tools described here will help you bring sane logging with timestamps and log rotation to any program that only outputs to stdout.

Further reading:

December 11, 2008

Day 11 - Home away from home

Logging in to a machine that isn't your own workstation can be scary. You are subject to the decisions made in someone else's configuration files that don't always align with your own configurations: different shell, different default shell configuration, different default editor, different editor configuration, etc.

This is a scary and unproductive place. Suddenly 'ls' output is colored, or vim uses a different indenting configuration, or worse, the default editor is not your favorite editor (which doesn't have to be vim). Dedication to mastering your basic tools over time has helped you create the One True Configuration for each tool; deviation from this configuration means a loss of productivity. You need to bring your home (directory) with you.

When your home directory doesn't magically appear through the miracles of network filesystems, you may need to fix the problem another way. One potential solution is to make sure that you copy all your configuration files (.vimrc, .zshrc, whatever) to every host you're going to login to. This doesn't scale. Further, it means everyone else has to repeat the same process for their own files.

The fix is to create a system which automatically keeps your home directory, on every machine, populated with your configurations. You can do this minimally with revision control and a cron job, but I prefer to add rsync to this process.

Step one is make a place in your revision control system for people to create home directories. For example, declaring that the path /trunk/home in your repository is where you should dump your homedirectory contents. This means if my username were 'jordan' then I'd check my '.vimrc' in as '/trunk/home/jordan/.vimrc' and should expect it to show up on any system I have access to.

Step two is to pick a server that has access to both revision control and other servers. Set up a cron job here that will check out and keep-updated your entire /trunk/home path. Run an rsync daemon here that exports this /trunk/home for other servers to update with. Set the rsync module name to 'homedirs' for readability.

Step three is to deploy a cron job on every necessary server that copies down all the obvious files from someserver::homedirs with rsync. You do have automation that lets you install a cron job on all of your servers, right? ;)

Before you go and write the one line of rsync invocation that it would take to copy someserver::homedirs to /home, you should take care to note the potential security implications of doing this as root. If I have a file checked in called /home/jls/test/shadow, and on one of the servers I sneakily symlink /home/jls/test/ to /etc, and you run the rsync blindly as root, you just let me overwrite your /etc/shadow file (or something else evil). Malicious or accidental, doing a single rsync may not be the best solution.

The fix is to run the rsync as each user. You can get the list of users to copy down by running 'rsync someserver::homedirs' to get the list of directories, which should include your usernames. Check out the completed version of the sync home directories script.

You should now be able to modify your home directory files in revision control and have them automatically propogate without your assistance.

Further reading:

The 'run rsync as the user' security idea from Pete Fritchman.