golang.org/x/tools/gopls@v0.15.3/internal/debug/info.go (about) 1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package debug exports debug information for gopls. 6 package debug 7 8 import ( 9 "context" 10 "encoding/json" 11 "fmt" 12 "io" 13 "os" 14 "runtime" 15 "runtime/debug" 16 "strings" 17 18 "golang.org/x/tools/gopls/internal/version" 19 ) 20 21 type PrintMode int 22 23 const ( 24 PlainText = PrintMode(iota) 25 Markdown 26 HTML 27 JSON 28 ) 29 30 // ServerVersion is the format used by gopls to report its version to the 31 // client. This format is structured so that the client can parse it easily. 32 type ServerVersion struct { 33 *debug.BuildInfo 34 Version string 35 } 36 37 // VersionInfo returns the build info for the gopls process. If it was not 38 // built in module mode, we return a GOPATH-specific message with the 39 // hardcoded version. 40 func VersionInfo() *ServerVersion { 41 if info, ok := debug.ReadBuildInfo(); ok { 42 return &ServerVersion{ 43 Version: version.Version(), 44 BuildInfo: info, 45 } 46 } 47 return &ServerVersion{ 48 Version: version.Version(), 49 BuildInfo: &debug.BuildInfo{ 50 Path: "gopls, built in GOPATH mode", 51 GoVersion: runtime.Version(), 52 }, 53 } 54 } 55 56 // PrintServerInfo writes HTML debug info to w for the Instance. 57 func (i *Instance) PrintServerInfo(ctx context.Context, w io.Writer) { 58 workDir, _ := os.Getwd() 59 section(w, HTML, "Server Instance", func() { 60 fmt.Fprintf(w, "Start time: %v\n", i.StartTime) 61 fmt.Fprintf(w, "LogFile: %s\n", i.Logfile) 62 fmt.Fprintf(w, "pid: %d\n", os.Getpid()) 63 fmt.Fprintf(w, "Working directory: %s\n", workDir) 64 fmt.Fprintf(w, "Address: %s\n", i.ServerAddress) 65 fmt.Fprintf(w, "Debug address: %s\n", i.DebugAddress()) 66 }) 67 PrintVersionInfo(ctx, w, true, HTML) 68 section(w, HTML, "Command Line", func() { 69 fmt.Fprintf(w, "<a href=/debug/pprof/cmdline>cmdline</a>") 70 }) 71 } 72 73 // PrintVersionInfo writes version information to w, using the output format 74 // specified by mode. verbose controls whether additional information is 75 // written, including section headers. 76 func PrintVersionInfo(_ context.Context, w io.Writer, verbose bool, mode PrintMode) error { 77 info := VersionInfo() 78 if mode == JSON { 79 return printVersionInfoJSON(w, info) 80 } 81 82 if !verbose { 83 printBuildInfo(w, info, false, mode) 84 return nil 85 } 86 section(w, mode, "Build info", func() { 87 printBuildInfo(w, info, true, mode) 88 }) 89 return nil 90 } 91 92 func printVersionInfoJSON(w io.Writer, info *ServerVersion) error { 93 js, err := json.MarshalIndent(info, "", "\t") 94 if err != nil { 95 return err 96 } 97 _, err = fmt.Fprint(w, string(js)) 98 return err 99 } 100 101 func section(w io.Writer, mode PrintMode, title string, body func()) { 102 switch mode { 103 case PlainText: 104 fmt.Fprintln(w, title) 105 fmt.Fprintln(w, strings.Repeat("-", len(title))) 106 body() 107 case Markdown: 108 fmt.Fprintf(w, "#### %s\n\n```\n", title) 109 body() 110 fmt.Fprintf(w, "```\n") 111 case HTML: 112 fmt.Fprintf(w, "<h3>%s</h3>\n<pre>\n", title) 113 body() 114 fmt.Fprint(w, "</pre>\n") 115 } 116 } 117 118 func printBuildInfo(w io.Writer, info *ServerVersion, verbose bool, mode PrintMode) { 119 fmt.Fprintf(w, "%v %v\n", info.Path, version.Version()) 120 if !verbose { 121 return 122 } 123 printModuleInfo(w, info.Main, mode) 124 for _, dep := range info.Deps { 125 printModuleInfo(w, *dep, mode) 126 } 127 fmt.Fprintf(w, "go: %v\n", info.GoVersion) 128 } 129 130 func printModuleInfo(w io.Writer, m debug.Module, _ PrintMode) { 131 fmt.Fprintf(w, " %s@%s", m.Path, m.Version) 132 if m.Sum != "" { 133 fmt.Fprintf(w, " %s", m.Sum) 134 } 135 if m.Replace != nil { 136 fmt.Fprintf(w, " => %v", m.Replace.Path) 137 } 138 fmt.Fprintf(w, "\n") 139 }