Avoiding that Face Palm moment with Logrotate

A runaway log file brought down on a previously built Rails app I was involved in building recently, and the solution to the problem here is so simple and easy to implement that a) I feel like a total dunce for not having this setup here in the first place b) it's almost churlish not to list it here, for reference for someone else, in the hope that it saves them feeling this stupid themselves in the future, (oh, and keeps the site they're working on up...).

If you're not using Rail's own to rotate the log files it generates, it really is good idea to make sure any log files it does make are being rotated, to make sure you don't get caught out when that innocuous seeming development.log file from a few months back goes live ends up bringing down your site because it's since grown from a 6k file to a 7 gigiabyte one, and eaten all the space on your server.

Making sure this doesn't happen is a pretty simple process:

  • Find where the offending logfiles are eating up all your disk space.
  • Create a new logrotate entry pointing to them.
  • Trigger the logrotate daemon to test it
  • Relax and get on with your life

Okay lets run through this in more detail.

Find the offending logfiles

The first step here is to find where the logs are being created. This here is the cause of the problem on a lot of boxes running Rails apps, because if you're using Capistrano to deploy an app, and you're using a stock Passenger config then your logs will end up in somewhere that the logrotate daemon, the program that dutifully goes around compressing and sorting logfiles on your server, won't know where to look for by default.

Normally, you can expect to find these quietly ballooning log files somewhere like /home/deploy/app/shared/log/, or /rails/deploy/appname.production/shared/log/.

Create the new logrotate entry

Now that we know where the logs are that keep eating space, we can tell logrotate about them, to make sure they won't grow too large. Create a text file named railsapp (or whatever makes the most sense to you) in /etc/logrotate.d/, the default place to leave instructions for logrotate to follow:

 
/home/deploy/app/shared/log/*.log {
  daily
  missingok
  rotate 30
  compress
  delaycompress
  sharedscripts
  postrotate
    touch /home/deploy/app/current/tmp/restart.txt
  endscript
}

Looking at that line by line:

  • daily calls this script daily
  • missingok means it's okay if we're missing some log files, we'll still work without stopping
  • rotate 30 means keep the last 30 days of logs
  • compress yup, compress the logs (using gzip by default)
  • delaycompress means "wait til the next day before compressing this file, just incase there are still be processes writing to this logfile"
  • sharedscripts means only call the next postrotate script once for all the files that match the pattern above, instead of restarting for each file
  • postrotate ... endscript - this script here fires after a rotate, to restart the passenger server, so that future processes log to the fresh, empty logfile

If you want to learn more, this article by Jesse Andrews on how he uses it is an absolute gem.

Trigger the logrotate daemon

Now that we have a logrotate entry, lets check it if works now rather than going to bed and finding out we had mistyped the path, by forcing a log rotate with this command (note the -f flag):

logrotate -f /etc/logrotate.d/railsapp

Get on with your life

If that's worked, then huzzah! That should be one less thing to worry about when looking after a webapp - though the usual "do some real homework before putting absolute faith in and deploying on a production system" disclaimers apply. As ever with Linux, be sure to read the man pages before use.

nb. While it's true that Rails is actually smart enough to rotate its own logs if you remember to configure it to behave this way, learning how to use logrotate like this means we can use this on other apps too, without being too tied to a particular framework. Handy when you need it for a Merb, Sinatra, Django, or even Node.js project

  • Share/Bookmark
Posted in Coding, sysadmin | Tagged , , , | Leave a comment

Setting up a CentOS base box for development and testing with Vagrant

I've been using at Vagrant at work lately to make it easier to switch between environments on projects, and to help out when testing chef recipes.

These instructions are here to help me remember how I went about building the base machines. This post will almost change in the next week or so.

If you don't know what the tool Vagrant is, these instructions won't mean much without watching this screencast demonstrating what Vagrant does, and why you might want to use it. I'd suggest taking the 15 minutes or so to watch it before reading on if you're unfamiliar with the project, as by necessity, they focus on creating a base virtual machine to begin building your own recipes on, and don't explain how to use Chef, or give much background.

They draw heavily on a gist by the excellently named Zellyn Hunter, with some instructions from the relevant page on the opscode wiki.

For simplicity, they favour using yum where possible for managing packages because a) it forms the basis of so many recipes when writing cookbooks in chef when you use any RedHat based flavour of Linux, and b) it should stop this guide going obsolete so quickly.

Still with us? Lets begin.

Create a bare virtual machine

First of all, we need a virtual machine as a base. We're making a CentOS based box here, but there are also some pre-made Ubuntu based boxes available as well online linked to in the Vagrant Google Group.

In Virtual box, create a new virtual machine, giving it a descriptive name that fits the guidelines on the vagrant page. We're making a 64 bit system here, so we're need to select this in virtual box:

Create a new VirtualBox machine
- Name: vagrant-centos64
- Operating System: Linux
- Version: Red Hat

Because we're eventually making a .box file that we're want others to be able to download, we need to take this into account in the resources allocated to this virtual machine, so we're going to make a dynamic hard disk that scales up to a large size, but when empty doesn't take up much space, and we'll keep the memory allocated to this machine fairly modest too. Because we have no need for graphics, or USB ports we'll leave them out of our virtual machine as well.

The specs should look something like this:

  • Base Memory Size: 360 MB
  • Dynamically expanding storage 40 GB
  • 40 GB
  • Disabled Audio
  • Disabled USB

Put an OS on the virtual machine

To install the OS, we need to do two things a) make sure the architecture for the install media matches that of the virtual machines and b) make sure our net install we can download the rest of the software needed to build the machine.

First we'll fetch the relevant iso image to mount like a virtual boot disc on our virtual machine:

wget http://mirrors.kernel.org/centos/5.4/isos/x86_64/CentOS-5.4-x86_64-netinstall.iso

We're using a net install to begin with here, because the standard images available for us are too large to download over broadband if you share a connection in an office or and you don't have some direct fibre-optic cable or similarly zippy connection. You'll notice this image is the install image for a 64bit architecture - the process is the same is you're looking for a 32 bit based system instead, just install fetch the 32bit install iso instead.

Next we need to make we can connect to the internet and pull down the other binary files. You should have NAT (Network Address Translation) set in virtualbox, which lets your host machine act like a router.

So make sure you have ipv4 enabled, (but ipv6 switched off), and all you should need to do is have DHCP set as the way to gain a connection, and you should be able to connect to the internet to download software.

Now run when you boot the VM, choose linux-text mode, and when asked about formatting the drive, select the option to initialise the drive with a standard linux filesystem. When you're asked about and when asked about the installation process, choose the HTTP option, disable ipv6, and enter the following details to pull down the kernel:

  • HTTP Setup:
    • Web site name: mirrors.kernel.org
    • CentOS directory: centos/5.4/os/i386

When we're given the option to select the network, we need to have a fully qualified domain name (i.e. vagrant-centos-5-4.local, not just vagrant-centos-5-4)

We'll also want to remove as much software as possible by default, so we want to customize software installation, and make sure the following is unselected when we do:

- Dial-up networking
- Editors
- Text-based internet
- Base

Now typing things into a virtual machine terminal without copy and paste gets old quickly, so lets set up port-forwarding so we can ssh into our newly created Virtualbox. The simplest way to do this is using the following invocations on the command line. We're going to make any connections to our own host machine (i.e. our laptop) on port 2222, bounce to port 22 on the guest virtual machine, and specify that this is a TCP connection.

    VBoxManage setextradata <guestname> "VBoxInternal/Devices/pcnet/0/LUN#0/Config/ssh/HostPort" 2222
    VBoxManage setextradata <guestname> "VBoxInternal/Devices/pcnet/0/LUN#0/Config/ssh/GuestPort" 22
    VBoxManage setextradata <guestname> "VBoxInternal/Devices/pcnet/0/LUN#0/Config/ssh/Protocol" TCP

Install Chef, and the Guest Additions

Now that we have a working machine, we need to set it up to a) work with our file system so changes on our host box are reflected on it, and b) get chef on it, so we can move into config-management nirvana. First all lets add a few handy packages first though:

  # useful for every case
  yum install curl ftp rsync sudo time wget which
 
  # these are needed for building Virtualbox Additions
  yum install gcc bzip2 make kernel-devel-`uname -r`

With the software needed, it's worth clearing off some packages that we don't need;

  yum erase wireless-tools gtk2 libX11 hicolor-icon-theme avahi freetype bitstream-vera-fonts

Now that we have the prerequisites, we can now install chef, and and setup the two-way shared folders setup.

Shared folders

From the virtual box app, select Devices -> Install Guest Additions... from the menubar to make available the Virtual box disk image; we can then mount it, and depending on the architecture we're using, run the relevant guest additions script:

  # mount the Guest additions image thats available in dev/cdrom as a read-only disk on the mount point /mnt, using the iso9660 standard, 
  mount -o ro -t iso9660 /dev/cdrom /mnt
  sh /mnt/VBoxLinuxAdditions-amd64.run # this may be VBoxLinuxAdditions-x86.run, if you're making a 32bit VM instead

If you're experiencing sluggish performance with shared folders, it's worth checking that you have the latest version of Virtualbox' guest editions installed. Calling the sh /mnt/VBoxLinuxAdditions-amd64.run command will perform a clean installation of the extensions, which can help (we're still struggling with this issue, so if you have any pointers let us know in the comments!)

Install chef

We'll need to add a couple of new sources before we can install chef, from the ELFF and EPEL yum repos where more recent software packages are made available:

  rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm
  rpm -Uvh http://download.elff.bravenet.com/5/i386/elff-release-5-3.noarch.rpm

Now at this point we can now add chef. The -y means we don't have to manually okay it when it comes through. Feel free to ignore it.

  yum install chef -y
Create the Vagrant User

The convention with vagrant is to create a group for our vagrant user, to allow any users in that group to call commands with sudo without needing passwords (as you can imagine, this makes calling remote ssh commands much simpler):

    groupadd admin
    useradd -G admin vagrant
    passwd vagrant
    # choose "vagrant" as the password
Update visudo to for vagrant user

As mentioned before, we need to make a few changes to the visudo table, to allow the vagrant user to perform chef runs. In short, we need to update the PATH attribute, relax the ssh daemon's requirements before it'll accept commands sent over ssh, and create a special insecure key that grants access without needing passwords.

First of all, comment the line saying Defaults requiretty in the visudo file - this option makes having an interactive teletype terminal a requirement for sudo commands to be called, so remote ssh commands that use sudo won't work. Switching off lets us call these commands remotely.

# Defaults requiretty

Next tweak the Defaults env_keep entry, to add PATH, so when we switch to switch user, we still keep the same paths, like having the correct version of Ruby when calling ohai the tool that chef uses to check your system's setup against the desired one specified in your cookbooks:

 
  Defaults    env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR \
                          LS_COLORS MAIL PS1 PS2 QTDIR USERNAME \
                          LANG LC_ADDRESS LC_CTYPE LC_COLLATE LC_IDENTIFICATION \
                          LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC \
                          LC_PAPER LC_TELEPHONE LC_TIME LC_ALL LANGUAGE LINGUAS \
                          _XKB_CHARSET XAUTHORITY PATH" #make sure path is here

There's more on this here on stackoverflow

We're almost done now - we just need to supplement the PATH variable, to make admin simpler, by making commands like ifconfig available without needing to type the full path to them. You do this by adding this line to the .bashrc file for the vagrant user:

  export PATH=$PATH:/usr/sbin:/sbin

Next log out, then log back in in as the vagrant user to sort out the key based access. We're going to add an insecure key that will let anyone log in to this box, so bear that in mind if you're using this on any private boxes:

  mkdir .ssh
  chmod 755 .ssh
  curl http://github.com/mitchellh/vagrant/raw/master/keys/vagrant.pub > .ssh/authorized_keys
  chmod 644 .ssh/authorized_keys

Clean up after ourselves, and prepare for packaging the .box file

We'd like to keep the packaged VM size small if we can, so the next step is to clean up after ourselves somewhat with yum like so:

sudo yum clean headers packages dbcache expire-cache

That's all the work done in the virtual machine now. Now we need to package it up with a Vagrantfile, which lists any custom adjustments, which is where we list the port forwarding instructions using the Vagrant DSL. First we create a directory, and create the Vagrantfile, somewhat like we would with a git project:

  mkdir centos-vagrant-64
  cd centos-vagrant-64
  vagrant init

Next we add edit the Vagrantfile, to add the ssh port, so we can actually log into it:

  Vagrant::Config.run do |config|
    # Forward the SSH port. The 'forward_port_key' should match the
    # name of the forwarded port.
    config.ssh.forwarded_port_key = "ssh"
    config.vm.forward_port("ssh", 22, 2222)
  end

Now that we've prepared both the Virtual Machine, and the host environment, we can then package it up, to create a sharable virtual machine. If the virtual machine we created using virtualbox was called centos-vagrant-64, we'd pass that in like so:

  vagrant package --base my_base_box --include Vagrantfile

We'll end up with a large compress file named package.box, which will be our virtual machine, all package up for sharing.

We can load this into our list of virtual machines available to vagrant like so, by passing in a desired name, and the path to the file. We can also to this with boxes across the internet, as long as they end with the .box extension, and and they're formatted to according to the guidelines in Vagrant.

  vagrant add vagrant-centos5.4-x64 ./package.box 
  vagrant add precompiled-vagrant-32 http://remote.server/with/pre-made-boxes/vagrant-centos5.4-i32

Using these boxes:

Now that we have these boxes available to us, a project only needs to refer to them in their Vagrantfile like so:

config.vm.box = "precompiled-vagrant-32"

And you'll be able to develop using the same environment as the other developers.

Customizing this boxes

We can update vagrant boxes using this DSL, to update memory, number of virtual cpu's, or to forward more ports if need be. If we want to give this machine more resources, because it's running too slow, we can up the memory and cpu count:

  config.vm.customize do |vm|
    vm.memory_size = 2048
    vm.cpu_count = 2
  end

If we we're working with the web, we'll want to add another forwarded port, but remember to update the firewall rules too:

  Vagrant::Config.run do |config|
    # Forward apache
    config.vm.forward_port("web", 80, 8080)
  end

Now what?

This should give a decent grounding on how to prepare virtual machines for sharing with others, but be sure to check the extensive documentation on the Vagrant website.

If you're interested in giving Vagrant a spin, and you're using CentOS, you might want to try building a system using these boxes

  • Share/Bookmark
Posted in Journal | 2 Comments

After reading this, I think I’ll let someone else work on Solaris boxes in future

I was doing some research on StackOverflow today to find out more about using Chef-Solo to manage smaller numbers of virtual machines (i.e. less than 5 for example), and I came across this snippet on a confessional thread about the worst mistakes you've made as a sysadmin:

I had fun discovering the difference between the linux "killall" command (kills all processes matching the specified name, useful for stopping zombies) and the solaris "killall" command (kills all processes and halts the system, useful for stopping the production server in the middle of peak hours and getting all your co-workers to laugh at you for a week)

Remind me to avoid looking after any Solaris boxes at all costs from now on - if a fairly innocuous Linux command kills an entire system, I shudder to think what other pitfalls and pratfalls lie in wait for a poor sysadmin....

  • Share/Bookmark
Posted in Coding | Tagged , , , | 1 Comment

Slideshare’s UI guys are really rather good.

Every now and then, you come cross a piece interaction design that's so well executed, it'd be plain disrespectful not to write about it. Today, I had one of those moments on Slideshare.

annotated screenshot of slideshare

See? Very clever, these Slideshare chaps.

I wanted to favourite this presentation by Drew Houston, Dropbox Startup Lessons Learned, about how they applied lean startup principles internally at Dropbox, so I signed in to the site.

From there, I was 'upsold' into tagging the content (useful for me, but also useful for the site)

From there, I had already switched from being a passive consumer, to being an annotator, and from there it wasn't much of a jump to convert (note the deft use of clever micro-copy) to being a commenter, adding what (I hope) was some extra value to the page an increasing my engagement with the service.

Each step seemed natural, and unforced.

Wow, these guys are good.

  • Share/Bookmark
Posted in UX | Tagged , , | Leave a comment

Notes on Chef – Understanding Resources and Providers

Title: Understanding resources and providers in Chef
Date: 2010-05-07 08:36:45

Chef is a pretty huge system, and one area that I didn't quite follow before was how recipes described in cookbooks were actually executed on the client machines when they were run. One of the key ideas with chef is that when you're writing recipes, you're effectively decoupling the results you'd want from an action, from the implementation, so you end up with a cross platform way to perform a given task.

Resources and Providers

You do this primarily in chef by writing Resources, which are high level ways to describe an action, like install a software package, or edit a group or user, then writing a Provider, which describes how you might actually implement this action on a given platform, or server setup.

For example on the [group] resource, when you're on a Linux system, you'll use a provider like Chef::Provider::User::Useradd by default, which is effectively a wrapper around a compiled binary like useradd, but if you're running Chef a Mac OS box, the default provider would be Chef::Provider::User::Dscl, which is essentially the same kind of wrapper around the dscl command.

It's this abstraction layer that decouples the action, from the implementation, and without understanding this, you won't get too far when writing cookbooks.

An example - the Script Resource

A good example of resource and providers would be the Script resource, because it shows how the code you might write when using a resource ends up looking like a cross between bash and ruby.

    script "install_something" do
      interpreter "bash"
      user "root"
      cwd "/tmp"
      code <<-EOH
      wget http://www.example.com/tarball.tar.gz
      tar -zxf tarball.tar.gz
      cd tarball
      ./configure
      make
      make install
      EOH
    end

In the snippet above, we're doing a common task - downloading a tarfile, then doing the configure, make, make install dance to compile it, but in the the first few lines, we're telling the resource to use the bash provider, and to switch to the root user first, before running the command by calling actions and attributes that the Resource has made available to us. It pays to check the docs on the opscode page if you see a command that you don't recognise when looking at recipes, as they're often described in the actions or attributes section.

One trick peculiar to the Script resource, is this shortcut to run the same string of commands without needing to explicitly set the interpreter in the block:

    bash "install_something" do
    user "root"
      cwd "/tmp"
      code <<-EOH
      wget http://www.example.com/tarball.tar.gz
      tar -zxf tarball.tar.gz
      cd tarball
      ./configure
      make
      make install
      EOH
    end

As mentioned before, you have more than one Provider for a given resource. In this case, we currently have 5 different providers, that correspond to the main shells or interpreters for running scripts, listed below:

    Chef::Resource::Script::Bash   bash
    Chef::Resource::Script::Csh    csh
    Chef::Resource::Script::Perl   perl
    Chef::Resource::Script::Python python
    Chef::Resource::Script::Ruby   ruby

This post should give a some high level insight into how Resources and Providers work, but as ever, if you're working with Chef, and their wiki isn't in your bookmarks You're Doing it Wrong - check the relevant pages, and with some luck this powerful feature of chef should become a bit less cryptic.

  • Share/Bookmark
Posted in Coding | Tagged , , | Leave a comment

Going beyond typing cap deploy

I mentioned earlier that if you don't use Capistrano too much, you might not be aware it's designed in such a way that it can be called happily from within Ruby code as well as being called on the command line.

In fact, the snippets below from the rdoc pages for the project, given idea of what's going on under the hood, when you call cap deploy.

Here's the command when we call it straight from the command line, within a capified project:

`cap deploy update_code -vvvv`

Now here's the same command, wrapped with a very lightweight ruby sprinkling of ruby, that wouldn't need us to supply any command line arguments ourselves.

require 'capistrano/cli'
  Capistrano::CLI.parse(%w(-vvvv -r config/deploy update_code)).execute!

There's a whole lot of clever stuff happening when the capistrano/cli.rb is called, like instantiating a configuration object that stores the arguments for parsing, and serves as a base for other methods, tasks and even full-on recipes to be attached to.

The snippet above is roughly equivalent to the code below, if we wanted to be explicit bout what how we wanted things to be done.

  require 'capistrano'
  require 'capistrano/cli'
  config = Capistrano::Configuration.new
  config.logger_level = Capistrano::Logger::TRACE
  config.set(:password) { Capistrano::CLI.password_prompt }
  config.load "config/deploy"
  config.update_code

While writing this post, I consulted the Capistrano docs on rdoc.info repeatedly, and I think at long last, I'm starting to see the appeal of Yard for documentation now. Now to find a fun little project to actually try it out on...

  • Share/Bookmark
Posted in Coding | Tagged , , , | Leave a comment

Making arrays with ruby, without those pesky commas

The most common way to create an array in Ruby is do this:

my_shiny_new_array = ["tom", "dick", "harry", "jonah", "percy", "jermaine"]

Thanks to its perly origins though, you also have a more idiomatic way to do this in Ruby, like so:

%w(tom dick harry jonah percy jermaine)

Because Ruby has such a flexible syntax, it's easy to forget that when you use some of it's more magical tricks like wrapping a series of words in %w() to create an array, you're really calling a method called %w, and passing in the the strings as params like any other method.

This trick works with other delimiting characters too, using {} or [] like below gives the same result.

# all these create an array in the same way
%w(tom dick harry jonah percy jermaine)
%w[tom dick harry jonah percy jermaine]
%w{tom dick harry jonah percy jermaine}

This post has been updated since I managed to forgot to wrap the strings in quotes, and it was pointed out by a commenter (thanks Jakub!)

  • Share/Bookmark
Posted in Journal | Tagged , , | 2 Comments

Poking around the Capistrano gem binary,

I've recently been trying to get an understanding of how Rubygems lets us 'require' external code libraries by looking at a typical gem binary, because wasn't too clear to me how everything worked under the hood, and when I've tried to modify existing gems, I've been left scratching my head, generally unable to progress beyond having nice ideas.

I've written commented the living daylights out the 'cap' command on my system, to help me understand how it works:

#!/Users/chrisadams/.rvm/rubies/ruby-1.8.7-p249/bin/ruby
#
# This file was generated by RubyGems.
#
# The application 'capistrano' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = "&gt;= 0"
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
version = $1
ARGV.shift
end
gem 'capistrano', version
load Gem.bin_path('capistrano', 'cap', version)

Lets look at the various parts in more detail, shall we?

require 'rubygems'

We use this to make previously downloaded gems accessible by name, instead of having to provide the full path to each ruby file.

version = ">= 0"

Here we're listing the minumum version needed for this the capistrano gem to work

if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
  version = $1
  ARGV.shift
end

This checks the for any version numbers passed in, then removes it from the array that the 'cap' command would normally proces when working out what you want to do.

gem 'capistrano', version

The 'gem' method is like using a 'require statement for a rubygem', but lets us be version specific, in case changes to a codebase on a version bump break functionality. Capistrano's API has changed a few times, and great chunks of the DSL it uses have been deprecated, so this check is worthwhile:

load Gem.bin_path('capistrano', 'cap', version)

This is the path that really gets the ball rolling. The 'bin_path' method executes a binary in the gem named with the first parameter (in this case, capistrano). The second parameter lets us specify which binary should be used in the gem, in case the name of the binary, 'cap' isn't the same as the name of the code library , 'capistrano'. This lets us store multiple binaries on the rubygem without too much fear of clashes in the namespace.

This should have helped demystify each line in a common ruby based binary command - in the next post, I'll touch on how Capistrano can be called from the command line, or inside a script, by instantiating config objects that control how the program is run when you're not directly calling it from a terminal.

  • Share/Bookmark
Posted in Coding, Journal | Tagged , , | 1 Comment

On blogging as a way to work out what you’re thinking

I really like how this recent post by Adam Greenfield starts. I'm normally in awe of his writing, and how vivid the picture is that he paints, of a near future of networked urbanism, and well thought through design. Seeing this disclaimer today makes him seem so much more fallible, and well... more like the rest of us:

This is a quickish post on a big and important topic, so I’d caution you against taking any of the following too terribly seriously. Blogging is generally how I best think things through, though, so I’d be grateful if you’d bear with me as I work out just what it is I mean to say.

Whenever I try to write something of substance, I'm usually paralysed by a fear of being wrong, or not expressing what I've been thinking about completely and concisely, and so the post I've started writing ends up languishing in my drafts folder, or on my computer, until it's a) out of date and irrelevant and abandoned b) no longer intelligble to me, because its largely notes and I don't remember what I was writing about when I come back to it.

So seeing this from a figure whose writing was one of the reasons I decided to throw most of my twenties into a career in technology, if incredibly refreshing, and writing on this blog here, it feels like a huge weight has been lifted off from my writing.

Lets see how long this lasts.

  • Share/Bookmark
Posted in Journal, meta | Tagged | Leave a comment

Painful times ahead

I recently read an article recommended by Tim Duckett, one of the talented Headshift alumni who I maintain a level of weak-tie twitter contact, and in it John Lanchester puts into perspective just how much of a financial mess the UK is:

Cuts of that magnitude have never been achieved in this country. Mrs Thatcher managed to cut some areas of public spending to zero growth; the difference between that and a contraction of 16 per cent is unimaginable. The Institute for Fiscal Studies – which admittedly specialises in bad news of this kind – thinks the numbers are, even in this dire prognosis, too optimistic.

What does that mean? According to Rowena Crawford, an IFS economist, quoted in the FT: ‘For the Ministry of Defence an 18 per cent cut means something on the scale of no longer employing the army.’

Later on, touches on just how unjustified the ridiculously large bonuses in the last twelve months really are:

This year, the levels of bonuses across the industry are unconscionable…thanks to the special measures currently in place the banks can borrow from their governments at, effectively, 0 per cent rates of interest. They can then invest the money at higher rates of interest, 5 to 7 per cent, say. This is a direct transfer of wealth from the taxpayer to the banks, and the only difference between it and an actual, physical licence to print money is that the banks don’t have a piece of paper with the words ‘Official Licence to Print Money’ written across the top.

The main point in the article seems to be that no matter which party wins this year, Britain’s financial situation is so dire that that most decisions a government could take have essentially been taken by the the bond markets that they’ll be beholden to.

It's a pretty depressing message, and the best he can do to find a upbeat ending is that the bonuses this year are so grotesquely huge, that they might represent bankers realising how broken the system is, and frantically last suppering before the public wakes up to this behaviour, and starts collectively calling for some effective regulation:

The proposals now being touted do not guarantee systemic safety, but taken together they will, for sure, make the system much less profitable. Maybe, just maybe, the bankers are pigging out this year because they suspect this is the last of the good times. If we’re looking for a glint of silver lining, does that count?

Jon Lanchester's writing doesn't leave you hopeful about the future, but he does write brilliantly (I think the correct phrase is entertainingly depressing) - go read it, it's a nice break from the ridiculous BigotGate coverage that's saturating the press right now.

  • Share/Bookmark
Posted in Economics | Tagged , , , | Leave a comment