The Elegant Chaos Blog

There comes a time in every programmers life when all the fancy symbolic debuggers let us down, and we have to fall back to that old standby, logging. Or to give it its full name “printf debugging”!

Actually there are lots of reasons why logging can be useful. Sometimes we have what I like to call a “heisenbug” - where the very act of stopping in a debugger to look at the problem causes the problem to disappear. Sometimes we have other timing issues. Sometimes we simply have too much data to analyse in real time, and we need a chance to process it or manually sift through it later.

In these cases the typical solution is to insert print statements into our code which output some text to the console or a file. In C this is typically printf(), or perhaps fprintf(). In Objective-C, we use NSLog instead. Problems ========

There are a few problems with logging code though:

  • we typically only want it whilst debugging
  • sometimes we only want it for a short time during a particular run
  • some log messages are more important than others
  • a large, well modularised, program may be under the control of many programmers, each with their own logging; often it all comes out together, leaving you drowning in output

Traditional Solution

Some of these problems can be solved, but it can get messy.

A typical solution is to define one or more macros which do the logging. By varying the definitions of the macros we can turn the logging on or off. This is a bit clumsy. You have to know that the macros exist, and where they are defined, and you have to recompile the program to change something. In a big program this may not be trivial - you may not even have source code for every framework.

In some solutions the logging macros that are defined include some concept of a level - for instance “warning”, “error”, and so on. This might allow us to vary the logging at runtime by only allowing through the log messages that match (or perhaps fall under) a given level. This can help, but it’s still clumsy. Logging messages don’t necessarily fall neatly into levels. Furthermore, messages from different modules will match the same level, so if you ask for a level you get everything at that level.

The ECLogging Solution

The ECLogging module sets out to solve these problems in a different way.


All logging is sent to a named channel, and there can be as many named channels as are needed. Named channels are intended to group logging messages by their purpose or their module, rather that by some concept of “level”.

Logging channels can of course be turned on and off. This can be done at runtime, and the particular configuration of channels that are enabled is saved on each machine, so that a programmer can set things up with only the channels that they want to see enabled. In fact, because of this, all channels default to being disabled, so you don’t get spammed with log output that you didn’t ask for.

Because channels in ECLogging are actual named objects, the logging system can iterate through them and present a user interface for their configuration.

Channels also come in two flavours - log and debug. Log channels exist in all builds. Debug channels only exist in debug builds, and the code associated with them is completely compiled away in release builds.


So log output goes in to the system via channels, but where does it come out?

The answer is handlers.

The logging system contains a number of predefined handlers, which know how to output to the console, the standard output and error streams, and to files on the disc. Custom handlers can be defined and added to do anything conceivable with log output - send it to another process over the network, for example.

By default, all channel output is sent to a global set of handlers. By choosing the handlers in this set you can easily influence where most of the logging output goes.

However, any logging channel can be configured to use it’s own custom set of handlers. In this way you can determine that some channels just go to the console, some just go to disc, and so on.

What Does It Look Like?

In use, the system is very similar to NSLog, except that you have to first define a channel, then direct output to it.


@implementation MyClass

- (void)myMethod
    ECLog(MyChannel, @"some message with params %@ %d", self, 123);


Add to this a small amount of code in your application delegate to initialise the system and install the handlers, and you’re good to go.

Drop in some additional iOS or Mac OS X user interface items, and you’ve got a way of configuring channels at runtime. Alternatively, you can just turn channels on and off in code, or by setting NSUserDefaults values.

Where To Find Out More

ECLogging can be found on github, including some decent documentation.

The ECLoggingExamples projects illustrate how to use the ECLogging module on both the Mac and iOS. They should be built from a workspace which also includes the ECLogging project.

Both of these samples are quite basic, and should definitely be regarded as a hint in the right direction, not a definitive illustration of everything that’s possible.


The library design is quite mature - it’s a meme I’ve implemented many times over the last decade or more, in different environments.

The implementation is quite immature, for the simple reason that I’m doing bits when I need them. It does work though, and I use it extensively, both in my own products and others that I contract on.

If anyone shows any interest in it, no doubt I’ll be motivated to get my finger out and improve it further!

[Updated Feb 2012 to fix github links, which have moved]


November 14, 2011

Ambientweet 1.0.1 is on it’s way, and has been submitted to the Mac App store today for review.

It brings with it a slew of syncing/caching updates which should result in more reliable fetching of tweets (especially after it’s been running for a while), and a faster startup.

The posting interface has also been improved - it looks more like a normal tweet window now, and it correctly deals with long urls, allowing you to post tweets that appear to be longer than 140 character, but which will be under the limit after Twitter has shortened the links.


It’s hard to make good products if you’re working in a vacuum. That’s why one of the things that we like most is hearing from people who’ve used our software, even if the message is “it’s broken”!

So if you send us a good suggestion, or a report of a genuine bug that we didn’t know about, there’s a good chance that we’ll send you a free license in return.

No promises mind you - if you send fifteen reports, each about an individual spelling error in the manual, then you probably won’t get fifteen licenses back :)


November 03, 2011

So, Apple have announced the deadline for developers to have their Mac App store apps work with sandboxing, and suddenly it’s March 2012, and not the November 2011 date that was widely understood amongst the developer community.

I guess I should be grateful, since the current sandboxing is distinctly half-baked as a plan. The only problem is, working on the assumption that we had to have sandboxing implemented by November, I’ve now got a relatively major update to Neu which uses it, and is waiting on just one sandboxing bug to be sorted out. Having removed the November deadline from developers, Apple have also conveniently removed the urgent need to fix the bug that’s holding me up.

So now I have to decide whether to hold back the Neu update - potentially for four months - whilst I wait for the bug fix (not a particularly attractive option), or to do more work turning sandboxing off again in Neu and splitting out the sandboxing-inspired changes from those that can ship regardless.


As I’ve said before, I’m broadly in favour of sandboxing, or at least the the motivation behind it. Anything we can do to protect users from malicious software is fine by me, as long as it doesn’t detract from what users actually want to do.

The way Apple have gone about implementing it though, has left a lot to be desired, and smacks of a certain hubris. They told us, rather than asked us, what we needed. Perhaps more worryingly, they got the answer quite substantially wrong. It’s good that they’ve seen sense and delayed it, but by announcing a new date they are still holding up a hostage to fortune, since we don’t have a fully working system yet.

Personally I think that they made a fundamental error in even considering using a metaphorical stick to force developers to adopt it. It would have been far better to use a carrot. If the Mac App store showed a subtle badge on sandboxed apps, with supporting material explaining that apps with the badge had “enhanced security” or some such phrase, it would create a positive incentive for developers which ought to translate directly into increased sales.

Using an application with “enhanced security” is going to be attractive to most users, regardless of exactly how much they understand about what the “enhancement” actually represents - but it leaves the choice in the hands of the user.

Whilst I’m not normally a great fan of marketing bullshit, or of overloading users with more information than they need, I think that this is a situation where presenting a simplified (but accurate) picture of the benefits of sandboxed apps is far preferable to forcing all apps to be sandboxed.


October 28, 2011

… and another one!

Neu 1.2b3 is available for the brave of heart!

This one has a rough implementation of the new UI for managing your templates.

Rather than a separate templates window, you can now right-click on a template in the main UI, and do various things to it directly (rename, delete, reveal, open), or you can choose “Edit Template…” to open an editing pane. This pain allows you to set some per-template preferences, including a keyboard shortcut.

Known Issues

In grid view, the context menu commands on templates currently operate on the selected template, which might not be the one that you clicked on! So be careful with the delete command!

Per-template keyboard shortcuts don’t work yet.

The “Rename Template…” command doesn’t work yet.

Due to a bug in sandboxing, when overwriting an existing document you will be asked “Do you want to replace?” but if you say OK the creation will fail. The workaround for now is simply to give the new document a different name. Neu will always default to a unique name for the file, so this shouldn’t affect many people.