Merge pull request #126 from github/lightstep
ghcs: add --lightstep flag for tracing
This commit is contained in:
commit
0afdcdec84
2 changed files with 96 additions and 23 deletions
32
api/api.go
32
api/api.go
|
|
@ -18,6 +18,8 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
)
|
||||
|
||||
const githubAPI = "https://api.github.com"
|
||||
|
|
@ -42,7 +44,7 @@ func (a *API) GetUser(ctx context.Context) (*User, error) {
|
|||
}
|
||||
|
||||
a.setHeaders(req)
|
||||
resp, err := a.client.Do(req)
|
||||
resp, err := a.do(ctx, req, "/user")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error making request: %v", err)
|
||||
}
|
||||
|
|
@ -87,7 +89,7 @@ func (a *API) GetRepository(ctx context.Context, nwo string) (*Repository, error
|
|||
}
|
||||
|
||||
a.setHeaders(req)
|
||||
resp, err := a.client.Do(req)
|
||||
resp, err := a.do(ctx, req, "/repos/*")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error making request: %v", err)
|
||||
}
|
||||
|
|
@ -156,7 +158,7 @@ func (a *API) ListCodespaces(ctx context.Context, user *User) ([]*Codespace, err
|
|||
}
|
||||
|
||||
a.setHeaders(req)
|
||||
resp, err := a.client.Do(req)
|
||||
resp, err := a.do(ctx, req, "/vscs_internal/user/*/codespaces")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error making request: %v", err)
|
||||
}
|
||||
|
|
@ -204,7 +206,7 @@ func (a *API) GetCodespaceToken(ctx context.Context, ownerLogin, codespaceName s
|
|||
}
|
||||
|
||||
a.setHeaders(req)
|
||||
resp, err := a.client.Do(req)
|
||||
resp, err := a.do(ctx, req, "/vscs_internal/user/*/codespaces/*/token")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error making request: %v", err)
|
||||
}
|
||||
|
|
@ -238,7 +240,7 @@ func (a *API) GetCodespace(ctx context.Context, token, owner, codespace string)
|
|||
}
|
||||
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
resp, err := a.client.Do(req)
|
||||
resp, err := a.do(ctx, req, "/vscs_internal/user/*/codespaces/*")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error making request: %v", err)
|
||||
}
|
||||
|
|
@ -272,7 +274,7 @@ func (a *API) StartCodespace(ctx context.Context, token string, codespace *Codes
|
|||
}
|
||||
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
resp, err := a.client.Do(req)
|
||||
resp, err := a.do(ctx, req, "/vscs_internal/proxy/environments/*/start")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error making request: %v", err)
|
||||
}
|
||||
|
|
@ -309,7 +311,7 @@ func (a *API) GetCodespaceRegionLocation(ctx context.Context) (string, error) {
|
|||
return "", fmt.Errorf("error creating request: %v", err)
|
||||
}
|
||||
|
||||
resp, err := a.client.Do(req)
|
||||
resp, err := a.do(ctx, req, req.URL.String())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error making request: %v", err)
|
||||
}
|
||||
|
|
@ -350,7 +352,7 @@ func (a *API) GetCodespacesSKUs(ctx context.Context, user *User, repository *Rep
|
|||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
a.setHeaders(req)
|
||||
resp, err := a.client.Do(req)
|
||||
resp, err := a.do(ctx, req, "/vscs_internal/user/*/skus")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error making request: %v", err)
|
||||
}
|
||||
|
|
@ -394,7 +396,7 @@ func (a *API) CreateCodespace(ctx context.Context, user *User, repository *Repos
|
|||
}
|
||||
|
||||
a.setHeaders(req)
|
||||
resp, err := a.client.Do(req)
|
||||
resp, err := a.do(ctx, req, "/vscs_internal/user/*/codespaces")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error making request: %v", err)
|
||||
}
|
||||
|
|
@ -424,7 +426,7 @@ func (a *API) DeleteCodespace(ctx context.Context, user *User, token, codespaceN
|
|||
}
|
||||
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
resp, err := a.client.Do(req)
|
||||
resp, err := a.do(ctx, req, "/vscs_internal/user/*/codespaces/*")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error making request: %v", err)
|
||||
}
|
||||
|
|
@ -456,7 +458,7 @@ func (a *API) GetCodespaceRepositoryContents(ctx context.Context, codespace *Cod
|
|||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
a.setHeaders(req)
|
||||
resp, err := a.client.Do(req)
|
||||
resp, err := a.do(ctx, req, "/repos/*/contents/*")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error making request: %v", err)
|
||||
}
|
||||
|
|
@ -488,6 +490,14 @@ func (a *API) GetCodespaceRepositoryContents(ctx context.Context, codespace *Cod
|
|||
return decoded, nil
|
||||
}
|
||||
|
||||
func (a *API) do(ctx context.Context, req *http.Request, spanName string) (*http.Response, error) {
|
||||
// TODO(adonovan): use NewRequestWithContext(ctx) and drop ctx parameter.
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, spanName)
|
||||
defer span.Finish()
|
||||
req = req.WithContext(ctx)
|
||||
return a.client.Do(req)
|
||||
}
|
||||
|
||||
func (a *API) setHeaders(req *http.Request) {
|
||||
req.Header.Set("Authorization", "Bearer "+a.token)
|
||||
req.Header.Set("Accept", "application/vnd.github.v3+json")
|
||||
|
|
|
|||
|
|
@ -4,8 +4,13 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/lightstep/lightstep-tracer-go"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
@ -18,22 +23,32 @@ func main() {
|
|||
|
||||
var version = "DEV"
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "ghcs",
|
||||
SilenceUsage: true, // don't print usage message after each error (see #80)
|
||||
SilenceErrors: false, // print errors automatically so that main need not
|
||||
Long: `Unofficial CLI tool to manage GitHub Codespaces.
|
||||
var rootCmd = newRootCmd()
|
||||
|
||||
func newRootCmd() *cobra.Command {
|
||||
var lightstep string
|
||||
|
||||
root := &cobra.Command{
|
||||
Use: "ghcs",
|
||||
SilenceUsage: true, // don't print usage message after each error (see #80)
|
||||
SilenceErrors: false, // print errors automatically so that main need not
|
||||
Long: `Unofficial CLI tool to manage GitHub Codespaces.
|
||||
|
||||
Running commands requires the GITHUB_TOKEN environment variable to be set to a
|
||||
token to access the GitHub API with.`,
|
||||
Version: version,
|
||||
Version: version,
|
||||
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if os.Getenv("GITHUB_TOKEN") == "" {
|
||||
return tokenError
|
||||
}
|
||||
return nil
|
||||
},
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if os.Getenv("GITHUB_TOKEN") == "" {
|
||||
return tokenError
|
||||
}
|
||||
return initLightstep(lightstep)
|
||||
},
|
||||
}
|
||||
|
||||
root.PersistentFlags().StringVar(&lightstep, "lightstep", "", "Lightstep tracing endpoint (service:token@host:port)")
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
var tokenError = errors.New("GITHUB_TOKEN is missing")
|
||||
|
|
@ -45,3 +60,51 @@ func explainError(w io.Writer, err error) {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
// initLightstep parses the --lightstep=service:token@host:port flag and
|
||||
// enables tracing if non-empty.
|
||||
func initLightstep(config string) error {
|
||||
if config == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
cut := func(s, sep string) (pre, post string) {
|
||||
if i := strings.Index(s, sep); i >= 0 {
|
||||
return s[:i], s[i+len(sep):]
|
||||
}
|
||||
return s, ""
|
||||
}
|
||||
|
||||
// Parse service:token@host:port.
|
||||
serviceToken, hostPort := cut(config, "@")
|
||||
service, token := cut(serviceToken, ":")
|
||||
host, port := cut(hostPort, ":")
|
||||
portI, err := strconv.Atoi(port)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid Lightstep configuration: %s", config)
|
||||
}
|
||||
|
||||
opentracing.SetGlobalTracer(lightstep.NewTracer(lightstep.Options{
|
||||
AccessToken: token,
|
||||
Collector: lightstep.Endpoint{
|
||||
Host: host,
|
||||
Port: portI,
|
||||
Plaintext: false,
|
||||
},
|
||||
Tags: opentracing.Tags{
|
||||
lightstep.ComponentNameKey: service,
|
||||
},
|
||||
}))
|
||||
|
||||
// Report failure to record traces.
|
||||
lightstep.SetGlobalEventHandler(func(ev lightstep.Event) {
|
||||
switch ev := ev.(type) {
|
||||
case lightstep.EventStatusReport, lightstep.MetricEventStatusReport:
|
||||
// ignore
|
||||
default:
|
||||
log.Printf("[trace] %s", ev)
|
||||
}
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue