Issue 1:
% go get labix.org/v2/mgo
% go test -i -race labix.org/v2/mgo

This goes into an infinite loop and eats
up arbitrary amounts of memory when doing so.

I instrumented genlist to print out the
list nodes if it had traversed more than a million:

print("genlist %p; node %J\n", l, l->n);

A sample output is this:

genlist 7ffff4338a30; node u(100) l(5503) tc(1)
genlist 7ffff441cf30; node u(100) l(5503) tc(1)
genlist 7ffff4338a30; node u(100) l(5503) tc(1)
genlist 7ffff441cf30; node u(100) l(5503) tc(1)
genlist 7ffff4338a30; node u(100) l(5503) tc(1)

The command line that failed in this way was:
/home/rog/go/pkg/tool/linux_amd64/6g -o $WORK/labix.org/v2/mgo/_obj/_go_.6 -race -p
labix.org/v2/mgo -complete -D _/home/rog/src/go/src/labix.org/v2/mgo -I $WORK -I
/home/rog/src/go/pkg/linux_amd64_race ./auth.go ./cluster.go ./doc.go ./gridfs.go
./log.go ./queue.go ./server.go ./session.go ./socket.go ./stats.go

I've verified that this behaviour occurs both on tip (a6a9792f94ac)
and go1.1.1.

Issue 2:
Motivation

Go stdlib provides a log.Logger that is widely used in both Go programs and Go libraries (eg. most notably in http.Server) as a standardized logging component.

However, the current implementation of the log.Logger enforces a specific logging format with limited flexibility which requires text parsing to allow it to be connected to any other logging system implementation through the swappable io.Writer interface. This adds complexity and overhead. The other alternative of directly using third party logging libraries is not very scalable both because existing libraries including components like http.Server in the stdlib expect log.Logger and because of network effects of stdlib.

Proposal

This proposes a minor change to the log package to make log.Logger more extensible in a fully backwards compatible by allowing Logger.Output() to write logs using custom logging implementations.

We do this by defining a function type called OutputFn with the same function signature as the current Logger.Output() and introducing an unexported field outputfn in Logger to hold the function that should be used for output much like we use the out field to hold the io.Writer currently. By default, log.New() will set the outputfn to the current implementation which is moved to Logger.DefOutputFn(). This can be swapped to any other OutputFn implementation by calling Logger.SetOutputFn() in the same way as we currently can swap io.Writer by calling Logger.SetOutput()

For the top level log package, we provide log.SetOutputFn() and log.SetDefOutputFn() to set the OutputFn of the log.std logger and reset it to default.

Proof of Concept

I have implemented a proof of concept for this proposed change and added an example in the test suite that demonstrates logging to a Tab Separated Variable format. While in the example i am merely writing to a Writer, the Output could be to anything including over the network etc.

If this approach looks ok, I can package this into a CL incorporating any feedback.

Rationale for the Approach

Most of the actual work of logging happens in Logger.Output() (and in the unexported Logger.formatHeader() called by it) which makes it a prime candidate for flexibility. We cannot change log.Logger into an interface due to Go1 compatibility promise and this approach therefore allows a lot of flexibility with a very minor change.