using log package for a console, is there a way to prepend data instead of appending?

59 views
Skip to first unread message

Shaban

unread,
Mar 31, 2011, 2:48:27 AM3/31/11
to golang-nuts
hello,

my problem is i wanna use the log package to make a console that shows
the result of operations.
in such a console the topmost message should be the newest.
i am using a bytes.Buffer for that.

is there a way to make the Logger prepend logging messages into that
buffer instead of appending it?

Jessta

unread,
Mar 31, 2011, 2:53:12 AM3/31/11
to Shaban, golang-nuts

Why don't you just read it in reverse?

--
=====================
http://jessta.id.au

Shaban

unread,
Mar 31, 2011, 3:38:27 AM3/31/11
to golang-nuts
Actually thats what i did, which was a bit more complicated because
some of my logs are multiline.
It came down to checking lines that start with the timestamp format
chosen and then fiddling them in reverse.
The reason i mentioned it is not being a slacker.

Prepending logging Messages is not an obscure use case

so either:
People might have found elegant solutions to this problem (At least
more elegeant that mine)
or if there is no elegant solutions to bring this fact to attention.

I might be spoiled though most packages are so extremey nice :-)

On 31 Mrz., 08:53, Jessta <jes...@jessta.id.au> wrote:

roger peppe

unread,
Mar 31, 2011, 4:13:52 AM3/31/11
to Shaban, golang-nuts
On 31 March 2011 08:38, Shaban <mr.n...@googlemail.com> wrote:
> Actually thats what i did, which was a bit more complicated because
> some of my logs are multiline.
> It came  down to checking lines that start with the timestamp format
> chosen and then fiddling them in reverse.
> The reason i mentioned it is not being a slacker.
>
> Prepending logging Messages is not an obscure use case
>
> so either:
> People might have found elegant solutions to this problem (At least
> more elegeant that mine)
> or if there is no elegant solutions to bring this fact to attention.
>
> I might be spoiled though most packages are so extremey nice :-)

interfaces make it easy to get what you want,
as is often the case with Go...

note that the logging package uses an arbitrary
io.Writer to write the logged data. you can create
an io.Writer that stores its data in reverse order.

here's an example:

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}
}

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())
}

Shaban

unread,
Mar 31, 2011, 4:32:30 AM3/31/11
to golang-nuts
Awesome roger,

i just tried it and it works like a charm.
thanks a lot :)

On 31 Mrz., 10:13, roger peppe <rogpe...@gmail.com> wrote:

pascal bertrand

unread,
Mar 31, 2011, 6:46:15 PM3/31/11
to roger peppe, Shaban, golang-nuts
Hi Roger,

I have trouble with the following line in your code. Why do you use append([]byte(nil), data) instead of simply using data?
       w.msgs = &msg{append([]byte(nil), data...), w.msgs}

My best guess is to make a slice out of data, but it seems to already be one.
Most likely, there is a subtlety I am missing, but I can't pin it down with the spec.

Thanks for your help,
Pascal BERTRAND

Jessta

unread,
Mar 31, 2011, 11:32:08 PM3/31/11
to pascal bertrand, roger peppe, Shaban, golang-nuts
On Fri, Apr 1, 2011 at 9:46 AM, pascal bertrand
<pascal....@gmail.com> wrote:
> Hi Roger,
> I have trouble with the following line in your code. Why do you use
> append([]byte(nil), data) instead of simply using data?
>        w.msgs = &msg{append([]byte(nil), data...), w.msgs}
>
> My best guess is to make a slice out of data, but it seems to already be
> one.

It's a copy of data.
Instead of using data directly and having the same underlying array.
This appends the items in data to an empty slice with a different
underlying array.
copy() would also work, but would require more lines.
eg.
a := []byte(nil)
copy(a,data);
w.msgs = &msg{a, w.msgs}

- jessta

- jessta

--
=====================
http://jessta.id.au

Reply all
Reply to author
Forward
0 new messages