diff --git a/cmd/cli/commands.go b/cmd/cli/commands.go index f5fbd5b..b174052 100644 --- a/cmd/cli/commands.go +++ b/cmd/cli/commands.go @@ -19,6 +19,7 @@ import ( "strings" "time" + "github.com/docker/go-units" "github.com/kardianos/service" "github.com/minio/selfupdate" "github.com/olekukonko/tablewriter" @@ -48,17 +49,24 @@ func initLogCmd() *cobra.Command { } defer resp.Body.Close() switch resp.StatusCode { - case http.StatusOK: - mainLog.Load().Notice().Msg("runtime logs sent successfully") case http.StatusServiceUnavailable: mainLog.Load().Warn().Msg("runtime logs could only be sent once per minute") - default: - buf, err := io.ReadAll(resp.Body) - if err != nil { - mainLog.Load().Fatal().Err(err).Msg("failed to read response body") - } - mainLog.Load().Error().Msg("failed to send logs") - mainLog.Load().Error().Msg(string(buf)) + return + case http.StatusMovedPermanently: + mainLog.Load().Warn().Msg("runtime debugs log is not enabled") + mainLog.Load().Warn().Msg(`ctrld may be run without "--cd" flag or logging is already enabled`) + return + } + var logs logSentResponse + if err := json.NewDecoder(resp.Body).Decode(&logs); err != nil { + mainLog.Load().Fatal().Err(err).Msg("failed to decode sent logs result") + } + size := units.BytesSize(float64(logs.Size)) + if logs.Error == "" { + mainLog.Load().Notice().Msgf("runtime logs sent successfully (%s)", size) + } else { + mainLog.Load().Error().Msgf("failed to send logs (%s)", size) + mainLog.Load().Error().Msg(logs.Error) } }, } @@ -85,6 +93,11 @@ func initLogCmd() *cobra.Command { return case http.StatusBadRequest: mainLog.Load().Warn().Msg("runtime debugs log is not available") + buf, err := io.ReadAll(resp.Body) + if err != nil { + mainLog.Load().Fatal().Err(err).Msg("failed to read response body") + } + mainLog.Load().Warn().Msgf("ctrld process response:\n\n%s\n", string(buf)) return case http.StatusOK: } diff --git a/cmd/cli/control_server.go b/cmd/cli/control_server.go index b6deed5..7a33407 100644 --- a/cmd/cli/control_server.go +++ b/cmd/cli/control_server.go @@ -217,7 +217,7 @@ func (p *prog) registerControlServerHandler() { p.cs.register(viewLogsPath, http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) { data, err := p.logContent() if err != nil { - w.WriteHeader(http.StatusBadRequest) + http.Error(w, err.Error(), http.StatusBadRequest) return } if len(data) == 0 { @@ -236,7 +236,7 @@ func (p *prog) registerControlServerHandler() { } data, err := p.logContent() if err != nil { - w.WriteHeader(http.StatusBadRequest) + http.Error(w, err.Error(), http.StatusBadRequest) return } if len(data) == 0 { @@ -249,11 +249,17 @@ func (p *prog) registerControlServerHandler() { LogFile: logFile, } mainLog.Load().Debug().Msg("sending log file to ControlD server") + resp := logSentResponse{Size: len(data)} if err := controld.SendLogs(req, cdDev); err != nil { mainLog.Load().Error().Msgf("could not send log file to ControlD server: %v", err) - http.Error(w, err.Error(), http.StatusInternalServerError) + resp.Error = err.Error() + w.WriteHeader(http.StatusInternalServerError) } else { mainLog.Load().Debug().Msg("sending log file successfully") + w.WriteHeader(http.StatusOK) + } + if err := json.NewEncoder(w).Encode(&resp); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) } p.internalLogSent = time.Now() })) diff --git a/cmd/cli/log_writer.go b/cmd/cli/log_writer.go index 2e73391..7f12032 100644 --- a/cmd/cli/log_writer.go +++ b/cmd/cli/log_writer.go @@ -24,6 +24,11 @@ type logViewResponse struct { Data string `json:"data"` } +type logSentResponse struct { + Size int `json:"size"` + Error string `json:"error"` +} + // logWriter is an internal buffer to keep track of runtime log when no logging is enabled. type logWriter struct { mu sync.Mutex @@ -118,6 +123,9 @@ func (p *prog) logContent() ([]byte, error) { lw.mu.Lock() data = lw.buf.Bytes() lw.mu.Unlock() + if len(data) == 0 { + return nil, errors.New("internal log is empty") + } } else { if p.cfg.Service.LogPath == "" { return nil, nil @@ -127,6 +135,9 @@ func (p *prog) logContent() ([]byte, error) { return nil, err } data = buf + if len(data) == 0 { + return nil, errors.New("log file is empty") + } } return data, nil } diff --git a/go.mod b/go.mod index d9e924d..67fe9a2 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/ameshkov/dnsstamps v1.0.3 github.com/coreos/go-systemd/v22 v22.5.0 github.com/cuonglm/osinfo v0.0.0-20230921071424-e0e1b1e0bbbf + github.com/docker/go-units v0.5.0 github.com/frankban/quicktest v1.14.6 github.com/fsnotify/fsnotify v1.7.0 github.com/go-playground/validator/v10 v10.11.1 diff --git a/go.sum b/go.sum index 66c6a73..bcf1ee7 100644 --- a/go.sum +++ b/go.sum @@ -74,6 +74,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa h1:h8TfIT1xc8FWbwwpmHn1J5i43Y0uZP97GqasGCzSRJk= github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa/go.mod h1:Nx87SkVqTKd8UtT+xu7sM/l+LgXs6c0aHrlKusR+2EQ= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=