mirror of
https://github.com/minio/minio.git
synced 2025-02-02 17:35:58 -05:00
Add more bootstrap info in debug mode (#17362)
This commit is contained in:
parent
38342b1df5
commit
6e38d0f3ab
@ -24,6 +24,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -216,6 +217,7 @@ func verifyServerSystemConfig(ctx context.Context, endpointServerPools EndpointS
|
|||||||
for onlineServers < len(clnts)/2 {
|
for onlineServers < len(clnts)/2 {
|
||||||
for _, clnt := range clnts {
|
for _, clnt := range clnts {
|
||||||
if err := clnt.Verify(ctx, srcCfg); err != nil {
|
if err := clnt.Verify(ctx, srcCfg); err != nil {
|
||||||
|
bootstrapTrace(fmt.Sprintf("clnt.Verify: %v, endpoint: %v", err, clnt.endpoint))
|
||||||
if !isNetworkError(err) {
|
if !isNetworkError(err) {
|
||||||
logger.LogOnceIf(ctx, fmt.Errorf("%s has incorrect configuration: %w", clnt.String(), err), clnt.String())
|
logger.LogOnceIf(ctx, fmt.Errorf("%s has incorrect configuration: %w", clnt.String(), err), clnt.String())
|
||||||
incorrectConfigs = append(incorrectConfigs, fmt.Errorf("%s has incorrect configuration: %w", clnt.String(), err))
|
incorrectConfigs = append(incorrectConfigs, fmt.Errorf("%s has incorrect configuration: %w", clnt.String(), err))
|
||||||
@ -264,7 +266,11 @@ func newBootstrapRESTClients(endpointServerPools EndpointServerPools) []*bootstr
|
|||||||
|
|
||||||
// Only proceed for remote endpoints.
|
// Only proceed for remote endpoints.
|
||||||
if !endpoint.IsLocal {
|
if !endpoint.IsLocal {
|
||||||
clnts = append(clnts, newBootstrapRESTClient(endpoint))
|
cl := newBootstrapRESTClient(endpoint)
|
||||||
|
if serverDebugLog {
|
||||||
|
cl.restClient.TraceOutput = os.Stdout
|
||||||
|
}
|
||||||
|
clnts = append(clnts, cl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,6 +396,9 @@ func configRetriableErrors(err error) bool {
|
|||||||
|
|
||||||
func bootstrapTrace(msg string) {
|
func bootstrapTrace(msg string) {
|
||||||
globalBootstrapTracer.Record(msg, 2)
|
globalBootstrapTracer.Record(msg, 2)
|
||||||
|
if serverDebugLog {
|
||||||
|
logger.Info(fmt.Sprint(time.Now().Round(time.Millisecond).Format(time.RFC3339), " bootstrap: ", msg))
|
||||||
|
}
|
||||||
|
|
||||||
if globalTrace.NumSubscribers(madmin.TraceBootstrap) == 0 {
|
if globalTrace.NumSubscribers(madmin.TraceBootstrap) == 0 {
|
||||||
return
|
return
|
||||||
@ -516,30 +519,38 @@ func serverMain(ctx *cli.Context) {
|
|||||||
setDefaultProfilerRates()
|
setDefaultProfilerRates()
|
||||||
|
|
||||||
// Initialize globalConsoleSys system
|
// Initialize globalConsoleSys system
|
||||||
|
bootstrapTrace("newConsoleLogger")
|
||||||
globalConsoleSys = NewConsoleLogger(GlobalContext)
|
globalConsoleSys = NewConsoleLogger(GlobalContext)
|
||||||
logger.AddSystemTarget(GlobalContext, globalConsoleSys)
|
logger.AddSystemTarget(GlobalContext, globalConsoleSys)
|
||||||
|
|
||||||
// Perform any self-tests
|
// Perform any self-tests
|
||||||
|
bootstrapTrace("selftests")
|
||||||
bitrotSelfTest()
|
bitrotSelfTest()
|
||||||
erasureSelfTest()
|
erasureSelfTest()
|
||||||
compressSelfTest()
|
compressSelfTest()
|
||||||
|
|
||||||
// Handle all server environment vars.
|
// Handle all server environment vars.
|
||||||
|
bootstrapTrace("serverHandleEnvVars")
|
||||||
serverHandleEnvVars()
|
serverHandleEnvVars()
|
||||||
|
|
||||||
// Handle all server command args.
|
// Handle all server command args.
|
||||||
|
bootstrapTrace("serverHandleCmdArgs")
|
||||||
serverHandleCmdArgs(ctx)
|
serverHandleCmdArgs(ctx)
|
||||||
|
|
||||||
// Initialize KMS configuration
|
// Initialize KMS configuration
|
||||||
|
bootstrapTrace("handleKMSConfig")
|
||||||
handleKMSConfig()
|
handleKMSConfig()
|
||||||
|
|
||||||
// Set node name, only set for distributed setup.
|
// Set node name, only set for distributed setup.
|
||||||
|
bootstrapTrace("setNodeName")
|
||||||
globalConsoleSys.SetNodeName(globalLocalNodeName)
|
globalConsoleSys.SetNodeName(globalLocalNodeName)
|
||||||
|
|
||||||
// Initialize all help
|
// Initialize all help
|
||||||
|
bootstrapTrace("initHelp")
|
||||||
initHelp()
|
initHelp()
|
||||||
|
|
||||||
// Initialize all sub-systems
|
// Initialize all sub-systems
|
||||||
|
bootstrapTrace("initAllSubsystems")
|
||||||
initAllSubsystems(GlobalContext)
|
initAllSubsystems(GlobalContext)
|
||||||
|
|
||||||
// Is distributed setup, error out if no certificates are found for HTTPS endpoints.
|
// Is distributed setup, error out if no certificates are found for HTTPS endpoints.
|
||||||
@ -556,11 +567,13 @@ func serverMain(ctx *cli.Context) {
|
|||||||
go func() {
|
go func() {
|
||||||
if !globalCLIContext.Quiet && !globalInplaceUpdateDisabled {
|
if !globalCLIContext.Quiet && !globalInplaceUpdateDisabled {
|
||||||
// Check for new updates from dl.min.io.
|
// Check for new updates from dl.min.io.
|
||||||
|
bootstrapTrace("checkUpdate")
|
||||||
checkUpdate(getMinioMode())
|
checkUpdate(getMinioMode())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Set system resources to maximum.
|
// Set system resources to maximum.
|
||||||
|
bootstrapTrace("setMaxResources")
|
||||||
setMaxResources()
|
setMaxResources()
|
||||||
|
|
||||||
// Verify kernel release and version.
|
// Verify kernel release and version.
|
||||||
@ -575,6 +588,7 @@ func serverMain(ctx *cli.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure server.
|
// Configure server.
|
||||||
|
bootstrapTrace("configureServerHandler")
|
||||||
handler, err := configureServerHandler(globalEndpoints)
|
handler, err := configureServerHandler(globalEndpoints)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(config.ErrUnexpectedError(err), "Unable to configure one of server's RPC services")
|
logger.Fatal(config.ErrUnexpectedError(err), "Unable to configure one of server's RPC services")
|
||||||
@ -585,6 +599,7 @@ func serverMain(ctx *cli.Context) {
|
|||||||
getCert = globalTLSCerts.GetCertificate
|
getCert = globalTLSCerts.GetCertificate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bootstrapTrace("xhttp.NewServer")
|
||||||
httpServer := xhttp.NewServer(getServerListenAddrs()).
|
httpServer := xhttp.NewServer(getServerListenAddrs()).
|
||||||
UseHandler(setCriticalErrorHandler(corsHandler(handler))).
|
UseHandler(setCriticalErrorHandler(corsHandler(handler))).
|
||||||
UseTLSConfig(newTLSConfig(getCert)).
|
UseTLSConfig(newTLSConfig(getCert)).
|
||||||
@ -595,10 +610,12 @@ func serverMain(ctx *cli.Context) {
|
|||||||
UseCustomLogger(log.New(io.Discard, "", 0)). // Turn-off random logging by Go stdlib
|
UseCustomLogger(log.New(io.Discard, "", 0)). // Turn-off random logging by Go stdlib
|
||||||
UseTCPOptions(globalTCPOptions)
|
UseTCPOptions(globalTCPOptions)
|
||||||
|
|
||||||
|
httpServer.TCPOptions.Trace = bootstrapTrace
|
||||||
go func() {
|
go func() {
|
||||||
globalHTTPServerErrorCh <- httpServer.Start(GlobalContext)
|
globalHTTPServerErrorCh <- httpServer.Start(GlobalContext)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
bootstrapTrace("setHTTPServer")
|
||||||
setHTTPServer(httpServer)
|
setHTTPServer(httpServer)
|
||||||
|
|
||||||
if globalIsDistErasure {
|
if globalIsDistErasure {
|
||||||
@ -609,6 +626,7 @@ func serverMain(ctx *cli.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bootstrapTrace("newObjectLayer")
|
||||||
newObject, err := newObjectLayer(GlobalContext, globalEndpoints)
|
newObject, err := newObjectLayer(GlobalContext, globalEndpoints)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logFatalErrs(err, Endpoint{}, true)
|
logFatalErrs(err, Endpoint{}, true)
|
||||||
@ -617,11 +635,15 @@ func serverMain(ctx *cli.Context) {
|
|||||||
xhttp.SetDeploymentID(globalDeploymentID)
|
xhttp.SetDeploymentID(globalDeploymentID)
|
||||||
xhttp.SetMinIOVersion(Version)
|
xhttp.SetMinIOVersion(Version)
|
||||||
|
|
||||||
|
bootstrapTrace("newSharedLock")
|
||||||
globalLeaderLock = newSharedLock(GlobalContext, newObject, "leader.lock")
|
globalLeaderLock = newSharedLock(GlobalContext, newObject, "leader.lock")
|
||||||
|
|
||||||
// Enable background operations for erasure coding
|
// Enable background operations for erasure coding
|
||||||
|
bootstrapTrace("initAutoHeal")
|
||||||
initAutoHeal(GlobalContext, newObject)
|
initAutoHeal(GlobalContext, newObject)
|
||||||
|
bootstrapTrace("initHealMRF")
|
||||||
initHealMRF(GlobalContext, newObject)
|
initHealMRF(GlobalContext, newObject)
|
||||||
|
bootstrapTrace("initBackgroundExpiry")
|
||||||
initBackgroundExpiry(GlobalContext, newObject)
|
initBackgroundExpiry(GlobalContext, newObject)
|
||||||
|
|
||||||
if !globalCLIContext.StrictS3Compat {
|
if !globalCLIContext.StrictS3Compat {
|
||||||
@ -658,15 +680,18 @@ func serverMain(ctx *cli.Context) {
|
|||||||
|
|
||||||
// Initialize users credentials and policies in background right after config has initialized.
|
// Initialize users credentials and policies in background right after config has initialized.
|
||||||
go func() {
|
go func() {
|
||||||
|
bootstrapTrace("globalIAMSys.Init")
|
||||||
globalIAMSys.Init(GlobalContext, newObject, globalEtcdClient, globalRefreshIAMInterval)
|
globalIAMSys.Init(GlobalContext, newObject, globalEtcdClient, globalRefreshIAMInterval)
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
if globalBrowserEnabled {
|
if globalBrowserEnabled {
|
||||||
|
bootstrapTrace("initConsoleServer")
|
||||||
srv, err := initConsoleServer()
|
srv, err := initConsoleServer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.FatalIf(err, "Unable to initialize console service")
|
logger.FatalIf(err, "Unable to initialize console service")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bootstrapTrace("setConsoleSrv")
|
||||||
setConsoleSrv(srv)
|
setConsoleSrv(srv)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -676,18 +701,22 @@ func serverMain(ctx *cli.Context) {
|
|||||||
|
|
||||||
// if we see FTP args, start FTP if possible
|
// if we see FTP args, start FTP if possible
|
||||||
if len(ctx.StringSlice("ftp")) > 0 {
|
if len(ctx.StringSlice("ftp")) > 0 {
|
||||||
|
bootstrapTrace("startFTPServer")
|
||||||
go startFTPServer(ctx)
|
go startFTPServer(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we see SFTP args, start SFTP if possible
|
// If we see SFTP args, start SFTP if possible
|
||||||
if len(ctx.StringSlice("sftp")) > 0 {
|
if len(ctx.StringSlice("sftp")) > 0 {
|
||||||
|
bootstrapTrace("startFTPServer")
|
||||||
go startSFTPServer(ctx)
|
go startSFTPServer(ctx)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if !globalDisableFreezeOnBoot {
|
if !globalDisableFreezeOnBoot {
|
||||||
|
bootstrapTrace("freezeServices")
|
||||||
defer unfreezeServices()
|
defer unfreezeServices()
|
||||||
|
defer bootstrapTrace("unfreezeServices")
|
||||||
t := time.AfterFunc(5*time.Minute, func() {
|
t := time.AfterFunc(5*time.Minute, func() {
|
||||||
logger.Info(color.Yellow("WARNING: Taking more time to initialize the config subsystem. Please set '_MINIO_DISABLE_API_FREEZE_ON_BOOT=true' to not freeze the APIs"))
|
logger.Info(color.Yellow("WARNING: Taking more time to initialize the config subsystem. Please set '_MINIO_DISABLE_API_FREEZE_ON_BOOT=true' to not freeze the APIs"))
|
||||||
})
|
})
|
||||||
@ -695,21 +724,27 @@ func serverMain(ctx *cli.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize data scanner.
|
// Initialize data scanner.
|
||||||
|
bootstrapTrace("initDataScanner")
|
||||||
initDataScanner(GlobalContext, newObject)
|
initDataScanner(GlobalContext, newObject)
|
||||||
|
|
||||||
// Initialize background replication
|
// Initialize background replication
|
||||||
|
bootstrapTrace("initBackgroundReplication")
|
||||||
initBackgroundReplication(GlobalContext, newObject)
|
initBackgroundReplication(GlobalContext, newObject)
|
||||||
|
|
||||||
|
bootstrapTrace("globalTransitionState.Init")
|
||||||
globalTransitionState.Init(newObject)
|
globalTransitionState.Init(newObject)
|
||||||
|
|
||||||
// Initialize batch job pool.
|
// Initialize batch job pool.
|
||||||
|
bootstrapTrace("newBatchJobPool")
|
||||||
globalBatchJobPool = newBatchJobPool(GlobalContext, newObject, 100)
|
globalBatchJobPool = newBatchJobPool(GlobalContext, newObject, 100)
|
||||||
|
|
||||||
// Initialize the license update job
|
// Initialize the license update job
|
||||||
|
bootstrapTrace("initLicenseUpdateJob")
|
||||||
initLicenseUpdateJob(GlobalContext, newObject)
|
initLicenseUpdateJob(GlobalContext, newObject)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
// Initialize transition tier configuration manager
|
// Initialize transition tier configuration manager
|
||||||
|
bootstrapTrace("globalTierConfigMgr.Init")
|
||||||
err := globalTierConfigMgr.Init(GlobalContext, newObject)
|
err := globalTierConfigMgr.Init(GlobalContext, newObject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.LogIf(GlobalContext, err)
|
logger.LogIf(GlobalContext, err)
|
||||||
@ -732,29 +767,36 @@ func serverMain(ctx *cli.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize bucket notification system.
|
// Initialize bucket notification system.
|
||||||
|
bootstrapTrace("initBucketTargets")
|
||||||
logger.LogIf(GlobalContext, globalEventNotifier.InitBucketTargets(GlobalContext, newObject))
|
logger.LogIf(GlobalContext, globalEventNotifier.InitBucketTargets(GlobalContext, newObject))
|
||||||
|
|
||||||
// List buckets to initialize bucket metadata sub-sys.
|
// List buckets to initialize bucket metadata sub-sys.
|
||||||
|
bootstrapTrace("listBuckets")
|
||||||
buckets, err := newObject.ListBuckets(GlobalContext, BucketOptions{})
|
buckets, err := newObject.ListBuckets(GlobalContext, BucketOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.LogIf(GlobalContext, fmt.Errorf("Unable to list buckets to initialize bucket metadata sub-system: %w", err))
|
logger.LogIf(GlobalContext, fmt.Errorf("Unable to list buckets to initialize bucket metadata sub-system: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize bucket metadata sub-system.
|
// Initialize bucket metadata sub-system.
|
||||||
|
bootstrapTrace("globalBucketMetadataSys.Init")
|
||||||
globalBucketMetadataSys.Init(GlobalContext, buckets, newObject)
|
globalBucketMetadataSys.Init(GlobalContext, buckets, newObject)
|
||||||
|
|
||||||
// initialize replication resync state.
|
// initialize replication resync state.
|
||||||
|
bootstrapTrace("go initResync")
|
||||||
go globalReplicationPool.initResync(GlobalContext, buckets, newObject)
|
go globalReplicationPool.initResync(GlobalContext, buckets, newObject)
|
||||||
|
|
||||||
// Initialize site replication manager after bucket metadata
|
// Initialize site replication manager after bucket metadata
|
||||||
|
bootstrapTrace("globalSiteReplicationSys.Init")
|
||||||
globalSiteReplicationSys.Init(GlobalContext, newObject)
|
globalSiteReplicationSys.Init(GlobalContext, newObject)
|
||||||
|
|
||||||
// Initialize quota manager.
|
// Initialize quota manager.
|
||||||
|
bootstrapTrace("globalBucketQuotaSys.Init")
|
||||||
globalBucketQuotaSys.Init(newObject)
|
globalBucketQuotaSys.Init(newObject)
|
||||||
|
|
||||||
// Populate existing buckets to the etcd backend
|
// Populate existing buckets to the etcd backend
|
||||||
if globalDNSConfig != nil {
|
if globalDNSConfig != nil {
|
||||||
// Background this operation.
|
// Background this operation.
|
||||||
|
bootstrapTrace("initFederatorBackend")
|
||||||
go initFederatorBackend(buckets, newObject)
|
go initFederatorBackend(buckets, newObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -771,6 +813,7 @@ func serverMain(ctx *cli.Context) {
|
|||||||
if region == "" {
|
if region == "" {
|
||||||
region = "us-east-1"
|
region = "us-east-1"
|
||||||
}
|
}
|
||||||
|
bootstrapTrace("globalMinioClient")
|
||||||
globalMinioClient, err = minio.New(globalLocalNodeName, &minio.Options{
|
globalMinioClient, err = minio.New(globalLocalNodeName, &minio.Options{
|
||||||
Creds: credentials.NewStaticV4(globalActiveCred.AccessKey, globalActiveCred.SecretKey, ""),
|
Creds: credentials.NewStaticV4(globalActiveCred.AccessKey, globalActiveCred.SecretKey, ""),
|
||||||
Secure: globalIsTLS,
|
Secure: globalIsTLS,
|
||||||
|
@ -120,8 +120,9 @@ func (listener *httpListener) Addrs() (addrs []net.Addr) {
|
|||||||
|
|
||||||
// TCPOptions specify customizable TCP optimizations on raw socket
|
// TCPOptions specify customizable TCP optimizations on raw socket
|
||||||
type TCPOptions struct {
|
type TCPOptions struct {
|
||||||
UserTimeout int // this value is expected to be in milliseconds
|
UserTimeout int // this value is expected to be in milliseconds
|
||||||
Interface string // this is a VRF device passed via `--interface` flag
|
Interface string // this is a VRF device passed via `--interface` flag
|
||||||
|
Trace func(msg string) // Trace when starting.
|
||||||
}
|
}
|
||||||
|
|
||||||
// newHTTPListener - creates new httpListener object which is interface compatible to net.Listener.
|
// newHTTPListener - creates new httpListener object which is interface compatible to net.Listener.
|
||||||
@ -162,6 +163,10 @@ func newHTTPListener(ctx context.Context, serverAddrs []string, opts TCPOptions)
|
|||||||
for _, serverAddr := range serverAddrs {
|
for _, serverAddr := range serverAddrs {
|
||||||
var l net.Listener
|
var l net.Listener
|
||||||
if l, err = listenCfg.Listen(ctx, "tcp", serverAddr); err != nil {
|
if l, err = listenCfg.Listen(ctx, "tcp", serverAddr); err != nil {
|
||||||
|
if opts.Trace != nil {
|
||||||
|
opts.Trace(fmt.Sprint("listenCfg.Listen: ", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
if isLocalhost && strings.HasPrefix(serverAddr, "[::1") {
|
if isLocalhost && strings.HasPrefix(serverAddr, "[::1") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -171,12 +176,18 @@ func newHTTPListener(ctx context.Context, serverAddrs []string, opts TCPOptions)
|
|||||||
tcpListener, ok := l.(*net.TCPListener)
|
tcpListener, ok := l.(*net.TCPListener)
|
||||||
if !ok {
|
if !ok {
|
||||||
err = fmt.Errorf("unexpected listener type found %v, expected net.TCPListener", l)
|
err = fmt.Errorf("unexpected listener type found %v, expected net.TCPListener", l)
|
||||||
|
if opts.Trace != nil {
|
||||||
|
opts.Trace(fmt.Sprint("net.TCPListener: ", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
if isLocalhost && strings.HasPrefix(serverAddr, "[::1") {
|
if isLocalhost && strings.HasPrefix(serverAddr, "[::1") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if opts.Trace != nil {
|
||||||
|
opts.Trace(fmt.Sprint("adding listener to ", tcpListener.Addr()))
|
||||||
|
}
|
||||||
tcpListeners = append(tcpListeners, tcpListener)
|
tcpListeners = append(tcpListeners, tcpListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,6 +207,9 @@ func newHTTPListener(ctx context.Context, serverAddrs []string, opts TCPOptions)
|
|||||||
acceptCh: make(chan acceptResult, len(tcpListeners)),
|
acceptCh: make(chan acceptResult, len(tcpListeners)),
|
||||||
}
|
}
|
||||||
listener.ctx, listener.ctxCanceler = context.WithCancel(ctx)
|
listener.ctx, listener.ctxCanceler = context.WithCancel(ctx)
|
||||||
|
if opts.Trace != nil {
|
||||||
|
opts.Trace(fmt.Sprint("opening ", len(listener.tcpListeners), " listeners"))
|
||||||
|
}
|
||||||
listener.start()
|
listener.start()
|
||||||
|
|
||||||
return listener, nil
|
return listener, nil
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@ -89,6 +90,9 @@ type Client struct {
|
|||||||
// Avoid metrics update if set to true
|
// Avoid metrics update if set to true
|
||||||
NoMetrics bool
|
NoMetrics bool
|
||||||
|
|
||||||
|
// TraceOutput will print debug information on non-200 calls if set.
|
||||||
|
TraceOutput io.Writer // Debug trace output
|
||||||
|
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
url *url.URL
|
url *url.URL
|
||||||
newAuthToken func(audience string) string
|
newAuthToken func(audience string) string
|
||||||
@ -222,6 +226,66 @@ func (r *respBodyMonitor) errorStatus(err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dumpHTTP - dump HTTP request and response.
|
||||||
|
func (c *Client) dumpHTTP(req *http.Request, resp *http.Response) {
|
||||||
|
// Starts http dump.
|
||||||
|
_, err := fmt.Fprintln(c.TraceOutput, "---------START-HTTP---------")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter out Signature field from Authorization header.
|
||||||
|
origAuth := req.Header.Get("Authorization")
|
||||||
|
if origAuth != "" {
|
||||||
|
req.Header.Set("Authorization", "**REDACTED**")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only display request header.
|
||||||
|
reqTrace, err := httputil.DumpRequestOut(req, false)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write request to trace output.
|
||||||
|
_, err = fmt.Fprint(c.TraceOutput, string(reqTrace))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only display response header.
|
||||||
|
var respTrace []byte
|
||||||
|
|
||||||
|
// For errors we make sure to dump response body as well.
|
||||||
|
if resp.StatusCode != http.StatusOK &&
|
||||||
|
resp.StatusCode != http.StatusPartialContent &&
|
||||||
|
resp.StatusCode != http.StatusNoContent {
|
||||||
|
respTrace, err = httputil.DumpResponse(resp, true)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
respTrace, err = httputil.DumpResponse(resp, false)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write response to trace output.
|
||||||
|
_, err = fmt.Fprint(c.TraceOutput, strings.TrimSuffix(string(respTrace), "\r\n"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ends the http dump.
|
||||||
|
_, err = fmt.Fprintln(c.TraceOutput, "---------END-HTTP---------")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns success.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Call - make a REST call with context.
|
// Call - make a REST call with context.
|
||||||
func (c *Client) Call(ctx context.Context, method string, values url.Values, body io.Reader, length int64) (reply io.ReadCloser, err error) {
|
func (c *Client) Call(ctx context.Context, method string, values url.Values, body io.Reader, length int64) (reply io.ReadCloser, err error) {
|
||||||
urlStr := c.url.String()
|
urlStr := c.url.String()
|
||||||
@ -263,6 +327,12 @@ func (c *Client) Call(ctx context.Context, method string, values url.Values, bod
|
|||||||
return nil, &NetworkError{err}
|
return nil, &NetworkError{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If trace is enabled, dump http request and response,
|
||||||
|
// except when the traceErrorsOnly enabled and the response's status code is ok
|
||||||
|
if c.TraceOutput != nil && resp.StatusCode != http.StatusOK {
|
||||||
|
c.dumpHTTP(req, resp)
|
||||||
|
}
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
// If server returns 412 pre-condition failed, it would
|
// If server returns 412 pre-condition failed, it would
|
||||||
// mean that authentication succeeded, but another
|
// mean that authentication succeeded, but another
|
||||||
|
Loading…
x
Reference in New Issue
Block a user