diff --git a/probe/controls/pipes.go b/probe/controls/pipes.go index ec4198eed..0f2779fab 100644 --- a/probe/controls/pipes.go +++ b/probe/controls/pipes.go @@ -54,3 +54,12 @@ func (p *pipe) Close() error { } return err2 } + +// DummyPipeClient implements PipeClient when running the probe in debugging mode +type DummyPipeClient struct{} + +// PipeConnection implements controls.PipeClient +func (DummyPipeClient) PipeConnection(appID, pipeID string, pipe xfer.Pipe) error { return nil } + +// PipeClose implements controls.PipeClient +func (DummyPipeClient) PipeClose(appID, pipeID string) error { return nil } diff --git a/prog/main.go b/prog/main.go index 390171f1e..f0776b65f 100644 --- a/prog/main.go +++ b/prog/main.go @@ -93,6 +93,7 @@ type flags struct { } type probeFlags struct { + printOnStdout bool token string httpListen string publishInterval time.Duration @@ -274,6 +275,7 @@ func setupFlags(flags *flags) { flag.Bool("app-only", false, "Only run the app.") // Probe flags + flag.BoolVar(&flags.probe.printOnStdout, "probe.publish.stdout", false, "Print reports on stdout instead of sending to app, for debugging") flag.StringVar(&flags.probe.token, serviceTokenFlag, "", "Token to authenticate with cloud.weave.works") flag.StringVar(&flags.probe.token, probeTokenFlag, "", "Token to authenticate with cloud.weave.works") flag.StringVar(&flags.probe.httpListen, "probe.http.listen", "", "listen address for HTTP profiling and instrumentation server") diff --git a/prog/probe.go b/prog/probe.go index e4275aa7d..15418b711 100644 --- a/prog/probe.go +++ b/prog/probe.go @@ -130,46 +130,62 @@ func probeMain(flags probeFlags, targets []appclient.Target) { xfer.ControlHandlerFunc(handlerRegistry.HandleControlRequest), ) } - clients := appclient.NewMultiAppClient(clientFactory, flags.noControls) - defer clients.Stop() - dnsLookupFn := net.LookupIP - if flags.resolver != "" { - dnsLookupFn = appclient.LookupUsing(flags.resolver) + var clients interface { + probe.ReportPublisher + controls.PipeClient } - resolver, err := appclient.NewResolver(appclient.ResolverConfig{ - Targets: targets, - Lookup: dnsLookupFn, - Set: clients.Set, - }) - if err != nil { - log.Fatalf("Failed to create resolver: %v", err) - return - } - defer resolver.Stop() + if flags.printOnStdout { + if len(targets) > 0 { + log.Warnf("Dumping to stdout only: targets %v will be ignored", targets) + } + clients = new(struct { + report.StdoutPublisher + controls.DummyPipeClient + }) + } else { + multiClients := appclient.NewMultiAppClient(clientFactory, flags.noControls) + defer multiClients.Stop() - if flags.weaveEnabled && flags.weaveHostname != "" { - dockerBridgeIP, err := network.GetFirstAddressOf(flags.dockerBridge) + dnsLookupFn := net.LookupIP + if flags.resolver != "" { + dnsLookupFn = appclient.LookupUsing(flags.resolver) + } + resolver, err := appclient.NewResolver(appclient.ResolverConfig{ + Targets: targets, + Lookup: dnsLookupFn, + Set: multiClients.Set, + }) if err != nil { - log.Errorf("Error getting docker bridge ip: %v", err) - } else { - weaveDNSLookup := appclient.LookupUsing(dockerBridgeIP + ":53") - weaveTargets, err := appclient.ParseTargets([]string{flags.weaveHostname}) + log.Fatalf("Failed to create resolver: %v", err) + return + } + defer resolver.Stop() + + if flags.weaveEnabled && flags.weaveHostname != "" { + dockerBridgeIP, err := network.GetFirstAddressOf(flags.dockerBridge) if err != nil { - log.Errorf("Failed to parse weave targets: %v", err) + log.Errorf("Error getting docker bridge ip: %v", err) } else { - weaveResolver, err := appclient.NewResolver(appclient.ResolverConfig{ - Targets: weaveTargets, - Lookup: weaveDNSLookup, - Set: clients.Set, - }) + weaveDNSLookup := appclient.LookupUsing(dockerBridgeIP + ":53") + weaveTargets, err := appclient.ParseTargets([]string{flags.weaveHostname}) if err != nil { - log.Errorf("Failed to create weave resolver: %v", err) + log.Errorf("Failed to parse weave targets: %v", err) } else { - defer weaveResolver.Stop() + weaveResolver, err := appclient.NewResolver(appclient.ResolverConfig{ + Targets: weaveTargets, + Lookup: weaveDNSLookup, + Set: multiClients.Set, + }) + if err != nil { + log.Errorf("Failed to create weave resolver: %v", err) + } else { + defer weaveResolver.Stop() + } } } } + clients = multiClients } p := probe.New(flags.spyInterval, flags.publishInterval, clients, flags.noControls) diff --git a/report/marshal.go b/report/marshal.go index 255f5a6fd..65921e3c5 100644 --- a/report/marshal.go +++ b/report/marshal.go @@ -26,6 +26,16 @@ func (s *dummySelfer) CodecEncodeSelf(encoder *codec.Encoder) { panic("This shouldn't happen: perhaps something has gone wrong in code generation?") } +// StdoutPublisher is useful when debugging +type StdoutPublisher struct{} + +// Publish implements probe.ReportPublisher +func (StdoutPublisher) Publish(rep Report) error { + handle := &codec.JsonHandle{Indent: 2} + handle.Canonical = true + return codec.NewEncoder(os.Stdout, handle).Encode(rep) +} + // WriteBinary writes a Report as a gzipped msgpack into a bytes.Buffer func (rep Report) WriteBinary() (*bytes.Buffer, error) { w := &bytes.Buffer{}