A recent post on the Go mailing list asked how to use the Go logging package to log messages in reverse order, so that they could be displayed most-recent-first in a console window.

The package gives no obvious way to do this, but the flexibility of Go interfaces makes it almost trivial to do. It took about 10 minutes to write the following code. The log package can use an arbitrary io.Writer for output so I defined a type, ReverseBuffer, with a Write method that stores all the data in a reverse-ordered linked list and a Reader method that returns an io.Reader that can be used to read the data back.

It would not take much longer to implement a size or message count limit on the list if desired.

I like the way that the language features worked together to make the design almost inevitable once I had thought of it. Once you have an implementation of an interface, everything else just works.

You can run it in the Go Playground to see it working.

package main import ( "io" "os" "log" ) type msg struct { data []byte next *msg } // ReverseBuffer is an implementation of io.Writer that stores data such // that it can later be read with the data from all writes reversed. type ReverseBuffer struct { msgs *msg } type reverseReader struct { data []byte msgs *msg } func (w *ReverseBuffer) Write(data []byte) (int, os.Error) { if len(data) == 0 { return 0, nil } w.msgs = &msg{append([]byte(nil), data...), w.msgs} return len(data), nil } // Reader returns a new io.Reader that can be used to read all the data // written to w. The data from more recent writes is returned first. func (w *ReverseBuffer) Reader() io.Reader { return &reverseReader{nil, w.msgs} } // Read implements io.Reader.Read. func (r *reverseReader) Read(data []byte) (int, os.Error) { if len(r.data) == 0 { if r.msgs == nil { return 0, os.EOF } r.data = r.msgs.data r.msgs = r.msgs.next } n := copy(data, r.data) r.data = r.data[n:] return n, nil } func main() { w := new(ReverseBuffer) out := log.New(w, "", log.Ldate|log.Ltime) out.Printf("one") out.Printf("two") out.Printf("three") io.Copy(os.Stdout, w.Reader()) }

Share this: Twitter

Facebook

Like this: Like Loading... Related