diff --git a/command/debug/debug.go b/command/debug/debug.go index e1544278bf66..695dc9ad9ebe 100644 --- a/command/debug/debug.go +++ b/command/debug/debug.go @@ -42,8 +42,13 @@ const ( // to ensure that all information can be collected in time debugMinDuration = 10 * time.Second - // The extension for archive files + // debugArchiveExtension is the extension for archive files debugArchiveExtension = ".tar.gz" + + // debugProtocolVersion is the version of the package that is + // generated. If this format changes interface, this version + // can be incremented so clients can selectively support packages + debugProtocolVersion = 1 ) func New(ui cli.Ui, shutdownCh <-chan struct{}) *cmd { @@ -77,6 +82,23 @@ type cmd struct { // validateTiming can be used to skip validation of interval, duration. This // is primarily useful for testing validateTiming bool + + index *debugIndex +} + +// debugIndex is used to manage the summary of all data recorded +// during the debug, to be written to json at the end of the run +// and stored at the root. Each attribute corresponds to a file or files. +type debugIndex struct { + // Version of the debug package + Version int + // Version of the target Consul agent + AgentVersion string + + Interval string + Duration string + + Targets []string } func (c *cmd) init() { @@ -150,6 +172,15 @@ func (c *cmd) Run(args []string) int { c.UI.Info(fmt.Sprintf(" Output: '%s'", archiveName)) c.UI.Info(fmt.Sprintf(" Capture: '%s'", strings.Join(c.capture, ", "))) + // Record some information for the index at the root of the archive + index := &debugIndex{ + Version: debugProtocolVersion, + AgentVersion: version, + Interval: c.interval.String(), + Duration: c.duration.String(), + Targets: c.capture, + } + // Add the extra grace period to ensure // all intervals will be captured within the time allotted c.duration = c.duration + debugDurationGrace @@ -161,7 +192,6 @@ func (c *cmd) Run(args []string) int { } // Capture dynamic information from the target agent, blocking for duration - // TODO(pearkes): figure out a cleaner way to do this if c.configuredTarget("metrics") || c.configuredTarget("logs") || c.configuredTarget("pprof") { err = c.captureDynamic() if err != nil { @@ -169,6 +199,19 @@ func (c *cmd) Run(args []string) int { } } + // Write the index document + idxMarshalled, err := json.MarshalIndent(index, "", "\t") + if err != nil { + c.UI.Error(fmt.Sprintf("Error marshalling index document: %v", err)) + return 1 + } + + err = ioutil.WriteFile(fmt.Sprintf("%s/index.json", c.output), idxMarshalled, 0644) + if err != nil { + c.UI.Error(fmt.Sprintf("Error creating index document: %v", err)) + return 1 + } + // Archive the data if configured to if c.archive { err = c.createArchive() diff --git a/command/debug/debug_test.go b/command/debug/debug_test.go index 162f80042aaf..57e47a348299 100644 --- a/command/debug/debug_test.go +++ b/command/debug/debug_test.go @@ -112,7 +112,7 @@ func TestDebugCommand_Archive(t *testing.T) { } // should only contain this one capture target - if h.Name != "debug/agent.json" { + if h.Name != "debug/agent.json" && h.Name != "debug/index.json" { t.Fatalf("archive contents do not match: %s", h.Name) } }