davecgh / go-spew

Implements a deep pretty printer for Go data structures to aid in debugging
ISC License
6.05k stars 364 forks source link

spew.Dump appears to not be enumerating all structures #55

Closed lowenna closed 7 years ago

lowenna commented 7 years ago

Are there any known issues where some structures aren't entirely printed. I submitted a PR to https://github.com/docker/docker/pull/27331 to add this additional debugging (this is a really cool capability, thank you!), and I noticed that in the docker context, almost everything got written out except the contents of container structure. Yet I can do things such as fmt.Println(container.ID) quite happily. Seeing this issue on Windows 10 x64/Windows Server 2016, go 1.7.1 and go-spew @ master/latest.

I haven't managed to repro this though outside of docker with a simpler test program though.

eg

 containers: (*container.memoryStore)(0xc042155ee0)({
  s: (map[string]*container.Container) (len=1) {
   (string) (len=64) "3bcc1fd2c454fa545ce23ff7b9976a27c916fa58ac450079e6e9aba79b991055": (*container.Container)(0xc042423d40)()
  },

Thanks, John.

davecgh commented 7 years ago

By default, spew will stop traversing into data structures if they implement the fmt.Stringer or error interface. You can override that behavior if you prefer with the following option:

    * ContinueOnMethod
        Enables recursion into types after invoking error and Stringer interface
        methods. Recursion after method invocation is disabled by default.

Example:

package main

import (
    "strconv"

    "github.com/davecgh/go-spew/spew"
)

type foo struct {
    field int
}

func (f foo) String() string {
    return "foo stringer" + strconv.Itoa(f.field)
}

func main() {
    spew.Dump(foo{field: 1})
    spew.Config.ContinueOnMethod = true
    spew.Dump(foo{field: 2})
}

Output:

(main.foo) foo stringer1
(main.foo) (foo stringer2) {
 field: (int) 2
}
davecgh commented 7 years ago

I should also note that if you're going to override behavior as my example shows, particularly in a package, you'll typically going to want to use a distinct ConfigState to ensure you don't interfere with the global state.

Using the same example above, that would mean:

    spew.Dump(foo{field: 1})
    cs := spew.NewDefaultConfig()
    cs.ContinueOnMethod = true
    cs.Dump(foo{field: 2})
davecgh commented 7 years ago

I'm gong to close this since I'm pretty sure that above is what you're running into. Feel free to comment back if that is not the case and I'll reopen the issue if necessary.