repo-updater: allow filter debug dumper by name (#37915)

This commit is contained in:
Joe Chen 2022-06-29 16:13:23 +08:00 committed by GitHub
parent 5c0a6c5600
commit 67f2ce8349
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 53 additions and 53 deletions

View File

@ -13,7 +13,6 @@ import (
"golang.org/x/time/rate"
"github.com/golang/gddo/httputil"
"github.com/graph-gophers/graphql-go/relay"
"github.com/opentracing/opentracing-go"
"github.com/prometheus/client_golang/prometheus"
@ -59,7 +58,7 @@ var stateHTMLTemplate string
// EnterpriseInit is a function that allows enterprise code to be triggered when dependencies
// created in Main are ready for use.
type EnterpriseInit func(logger log.Logger, db database.DB, store repos.Store, keyring keyring.Ring, cf *httpcli.Factory, server *repoupdater.Server) []debugserver.Dumper
type EnterpriseInit func(logger log.Logger, db database.DB, store repos.Store, keyring keyring.Ring, cf *httpcli.Factory, server *repoupdater.Server) map[string]debugserver.Dumper
type LazyDebugserverEndpoint struct {
repoUpdaterStateEndpoint http.HandlerFunc
@ -159,7 +158,7 @@ func Main(enterpriseInit EnterpriseInit) {
}
// All dependencies ready
var debugDumpers []debugserver.Dumper
debugDumpers := make(map[string]debugserver.Dumper)
if enterpriseInit != nil {
debugDumpers = enterpriseInit(logger, db, store, keyring.Default(), cf, server)
}
@ -230,7 +229,8 @@ func Main(enterpriseInit EnterpriseInit) {
globals.WatchExternalURL(nil)
debugserverEndpoints.repoUpdaterStateEndpoint = repoUpdaterStatsHandler(db, updateScheduler, debugDumpers)
debugDumpers["repos"] = updateScheduler
debugserverEndpoints.repoUpdaterStateEndpoint = repoUpdaterStatsHandler(db, debugDumpers)
debugserverEndpoints.listAuthzProvidersEndpoint = listAuthzProvidersHandler()
debugserverEndpoints.gitserverReposStatusEndpoint = gitserverReposStatusHandler(db)
debugserverEndpoints.rateLimiterStateEndpoint = rateLimiterStateHandler
@ -413,44 +413,20 @@ func listAuthzProvidersHandler() http.HandlerFunc {
}
}
func repoUpdaterStatsHandler(db database.DB, scheduler *repos.UpdateScheduler, debugDumpers []debugserver.Dumper) http.HandlerFunc {
func repoUpdaterStatsHandler(db database.DB, debugDumpers map[string]debugserver.Dumper) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
dumps := []any{
scheduler.DebugDump(r.Context(), db),
}
for _, dumper := range debugDumpers {
dumps = append(dumps, dumper.DebugDump())
}
wantDumper := r.URL.Query().Get("dumper")
wantFormat := r.URL.Query().Get("format")
const (
textPlain = "text/plain"
applicationJson = "application/json"
)
// Negotiate the content type.
contentTypeOffers := []string{textPlain, applicationJson}
defaultOffer := textPlain
contentType := httputil.NegotiateContentType(r, contentTypeOffers, defaultOffer)
// Allow users to override the negotiated content type so that e.g. browser
// users can easily request json by adding ?format=json to
// the URL.
switch r.URL.Query().Get("format") {
case "json":
contentType = applicationJson
}
switch contentType {
case applicationJson:
p, err := json.MarshalIndent(dumps, "", " ")
if err != nil {
http.Error(w, "failed to marshal snapshot: "+err.Error(), http.StatusInternalServerError)
// Showing the HTML version of repository syncing schedule as the default,
// also the only dumper that supports rendering the HTML version.
if (wantDumper == "" || wantDumper == "repos") && wantFormat != "json" {
reposDumper, ok := debugDumpers["repos"].(*repos.UpdateScheduler)
if !ok {
http.Error(w, "No debug dumper for repos found", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(p)
default:
// This case also applies for defaultOffer. Note that this is preferred
// over e.g. a 406 status code, according to the MDN:
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/406
@ -460,12 +436,29 @@ func repoUpdaterStatsHandler(db database.DB, scheduler *repos.UpdateScheduler, d
},
})
template.Must(tmpl.Parse(stateHTMLTemplate))
err := tmpl.Execute(w, dumps)
err := tmpl.Execute(w, reposDumper.DebugDump(r.Context(), db.ExternalServices()))
if err != nil {
http.Error(w, "failed to render template: "+err.Error(), http.StatusInternalServerError)
http.Error(w, "Failed to render template: "+err.Error(), http.StatusInternalServerError)
return
}
return
}
var dumps []any
for name, dumper := range debugDumpers {
if wantDumper != "" && wantDumper != name {
continue
}
dumps = append(dumps, dumper.DebugDump(r.Context(), db.ExternalServices()))
}
p, err := json.MarshalIndent(dumps, "", " ")
if err != nil {
http.Error(w, "Failed to marshal dumps: "+err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(p)
}
}

View File

@ -14,13 +14,11 @@
<body>
<div class="container">
{{$schedulerDump := index . 0}}
{{if gt (len .) 1}}
<div class="alert alert-info mt-5 mx-auto text-center" onclick="loadJSON()" role="button">
To view additional debug dumps, please request a JSON response
<i class="fas fa-link ml-2"></i>
</div>
{{end}}
{{$schedulerDump := .}}
<div class="alert alert-info mt-5 mx-auto text-center" onclick="loadJSON()" role="button">
To view additional debug dumps, please request a JSON response.
<i class="fas fa-link ml-2"></i>
</div>
<div class="mt-5 w-9/12" id="Index">
<li><a href="#Schedule">Schedule</a></li>

View File

@ -24,6 +24,7 @@ import (
"github.com/sourcegraph/sourcegraph/internal/authz"
"github.com/sourcegraph/sourcegraph/internal/conf"
"github.com/sourcegraph/sourcegraph/internal/database"
"github.com/sourcegraph/sourcegraph/internal/debugserver"
"github.com/sourcegraph/sourcegraph/internal/errcode"
"github.com/sourcegraph/sourcegraph/internal/extsvc"
"github.com/sourcegraph/sourcegraph/internal/extsvc/github"
@ -1323,7 +1324,7 @@ func (s *PermsSyncer) runSchedule(ctx context.Context) {
}
// DebugDump returns the state of the permissions syncer for debugging.
func (s *PermsSyncer) DebugDump() any {
func (s *PermsSyncer) DebugDump(_ context.Context, _ debugserver.ExternalServicesStore) any {
type requestInfo struct {
Meta *requestMeta
Acquired bool

View File

@ -39,7 +39,7 @@ func enterpriseInit(
keyring keyring.Ring,
cf *httpcli.Factory,
server *repoupdater.Server,
) (debugDumpers []debugserver.Dumper) {
) (debugDumpers map[string]debugserver.Dumper) {
debug, _ := strconv.ParseBool(os.Getenv("DEBUG"))
if debug {
logger.Info("enterprise edition")
@ -60,12 +60,13 @@ func enterpriseInit(
permsStore := edb.Perms(logger, db, timeutil.Now)
permsSyncer := authz.NewPermsSyncer(logger.Scoped("PermsSyncer", "repository and user permissions syncer"), db, repoStore, permsStore, timeutil.Now, ratelimit.DefaultRegistry)
go startBackgroundPermsSync(ctx, permsSyncer, db)
debugDumpers = append(debugDumpers, permsSyncer)
if server != nil {
server.PermsSyncer = permsSyncer
}
return debugDumpers
return map[string]debugserver.Dumper{
"repoPerms": permsSyncer,
}
}
// startBackgroundPermsSync sets up background permissions syncing.

View File

@ -1,6 +1,7 @@
package debugserver
import (
"context"
"encoding/json"
"fmt"
"net/http"
@ -17,6 +18,7 @@ import (
"github.com/sourcegraph/sourcegraph/internal/env"
"github.com/sourcegraph/sourcegraph/internal/goroutine"
"github.com/sourcegraph/sourcegraph/internal/httpserver"
"github.com/sourcegraph/sourcegraph/internal/types"
)
var addr = env.Get("SRC_PROF_HTTP", ":6060", "net/http/pprof http bind address.")
@ -70,10 +72,14 @@ type Service struct {
DefaultPath string
}
type ExternalServicesStore interface {
GetSyncJobs(ctx context.Context) ([]*types.ExternalServiceSyncJob, error)
}
// Dumper is a service which can dump its state for debugging.
type Dumper interface {
// DebugDump returns a snapshot of the current state.
DebugDump() any
DebugDump(ctx context.Context, esStore ExternalServicesStore) any
}
// NewServerRoutine returns a background routine that exposes pprof and metrics endpoints.

View File

@ -15,6 +15,7 @@ import (
"github.com/sourcegraph/sourcegraph/internal/api"
"github.com/sourcegraph/sourcegraph/internal/conf"
"github.com/sourcegraph/sourcegraph/internal/database"
"github.com/sourcegraph/sourcegraph/internal/debugserver"
"github.com/sourcegraph/sourcegraph/internal/gitserver"
gitserverprotocol "github.com/sourcegraph/sourcegraph/internal/gitserver/protocol"
"github.com/sourcegraph/sourcegraph/internal/mutablelimiter"
@ -397,7 +398,7 @@ func (s *UpdateScheduler) UpdateOnce(id api.RepoID, name api.RepoName) {
}
// DebugDump returns the state of the update scheduler for debugging.
func (s *UpdateScheduler) DebugDump(ctx context.Context, db database.DB) any {
func (s *UpdateScheduler) DebugDump(ctx context.Context, esStore debugserver.ExternalServicesStore) any {
data := struct {
Name string
UpdateQueue []*repoUpdate
@ -446,7 +447,7 @@ func (s *UpdateScheduler) DebugDump(ctx context.Context, db database.DB) any {
}
var err error
data.SyncJobs, err = db.ExternalServices().GetSyncJobs(ctx)
data.SyncJobs, err = esStore.GetSyncJobs(ctx)
if err != nil {
s.logger.Warn("getting external service sync jobs for debug page", log.Error(err))
}