diff --git a/api/middleware/log_http.go b/api/middleware/log_http.go index 8529717..d9fc33d 100644 --- a/api/middleware/log_http.go +++ b/api/middleware/log_http.go @@ -17,11 +17,12 @@ import ( ) type LogHTTPConfig struct { - Enabled bool - MaxBody int64 - MaxLogSize int - OutputPath string - UseGzip bool + Enabled bool + MaxBody int64 + MaxLogSize int + OutputPath string + UseGzip bool + LogResponse bool } type fileLogger struct { @@ -97,6 +98,23 @@ func ReloadFileLogger(conf *LogHTTPConfig) error { return nil } +// responseReadWriter helps read http response body. +type responseReadWriter struct { + http.ResponseWriter + response *bytes.Buffer +} + +func (ww *responseReadWriter) Write(data []byte) (int, error) { + ww.response.Write(data) + return ww.ResponseWriter.Write(data) +} + +func (ww *responseReadWriter) Flush() { + if f, ok := ww.ResponseWriter.(http.Flusher); ok { + f.Flush() + } +} + // LogHTTP logs http parameters from s3 request. func LogHTTP(l *zap.Logger, config *LogHTTPConfig) Func { var err error @@ -129,8 +147,18 @@ func LogHTTP(l *zap.Logger, config *LogHTTPConfig) Func { l.Warn(logs.FailedToGetRequestBody, zap.Error(err)) } } - httplog.Info(logs.RequestHTTP) - h.ServeHTTP(w, r) + if !config.LogResponse { + httplog.Info(logs.LogHTTP) + h.ServeHTTP(w, r) + } else { + var resp = bytes.Buffer{} + ww := &responseReadWriter{ResponseWriter: w, response: &resp} + h.ServeHTTP(ww, r) + if int64(resp.Len()) <= config.MaxBody { + httplog.With(zap.String("response", base64.StdEncoding.EncodeToString(resp.Bytes()))). + Info(logs.LogHTTP) + } + } }) } } diff --git a/api/middleware/log_http_stub.go b/api/middleware/log_http_stub.go index 556f030..eb890c3 100644 --- a/api/middleware/log_http_stub.go +++ b/api/middleware/log_http_stub.go @@ -10,11 +10,12 @@ import ( ) type LogHTTPConfig struct { - Enabled bool - MaxBody int64 - MaxLogSize int - OutputPath string - UseGzip bool + Enabled bool + MaxBody int64 + MaxLogSize int + OutputPath string + UseGzip bool + LogResponse bool } func LogHTTP(l *zap.Logger, _ *LogHTTPConfig) Func { diff --git a/cmd/s3-gw/app.go b/cmd/s3-gw/app.go index 74f5582..672098c 100644 --- a/cmd/s3-gw/app.go +++ b/cmd/s3-gw/app.go @@ -653,6 +653,7 @@ func (s *appSettings) updateHTTPLoggingSettings(cfg *viper.Viper, log *zap.Logge s.httpLogging.MaxLogSize = cfg.GetInt(cfgHTTPLoggingMaxLogSize) s.httpLogging.OutputPath = cfg.GetString(cfgHTTPLoggingDestination) s.httpLogging.UseGzip = cfg.GetBool(cfgHTTPLoggingGzip) + s.httpLogging.LogResponse = cfg.GetBool(cfgHTTPLoggingLogResponse) if err := s3middleware.ReloadFileLogger(s.httpLogging); err != nil { log.Error(logs.FailedToReloadHTTPFileLogger, zap.Error(err)) } diff --git a/cmd/s3-gw/app_settings.go b/cmd/s3-gw/app_settings.go index f01e665..a8f6739 100644 --- a/cmd/s3-gw/app_settings.go +++ b/cmd/s3-gw/app_settings.go @@ -85,6 +85,7 @@ const ( // Settings. cfgHTTPLoggingMaxLogSize = "http_logging.max_log_size" cfgHTTPLoggingDestination = "http_logging.destination" cfgHTTPLoggingGzip = "http_logging.gzip" + cfgHTTPLoggingLogResponse = "http_logging.log_response" // Wallet. cfgWalletPath = "wallet.path" @@ -777,6 +778,7 @@ func newSettings() *viper.Viper { v.SetDefault(cfgHTTPLoggingMaxLogSize, 50) v.SetDefault(cfgHTTPLoggingDestination, "stdout") v.SetDefault(cfgHTTPLoggingGzip, false) + v.SetDefault(cfgHTTPLoggingLogResponse, true) // pool: v.SetDefault(cfgPoolErrorThreshold, defaultPoolErrorThreshold) diff --git a/docs/configuration.md b/docs/configuration.md index f8eeb2d..276a018 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -387,6 +387,7 @@ http_logging: max_log_size: 20 gzip: true destination: stdout + log_response: true ``` | Parameter | Type | SIGHUP reload | Default value | Description | @@ -394,8 +395,9 @@ http_logging: | `enabled` | bool | yes | false | Flag to enable the logger. | | `max_body` | int | yes | 1024 | Max body size for log output in bytes. | | `max_log_size` | int | yes | 50 | Log file size threshold (in megabytes) to be moved in backup file. After reaching threshold, initial filename is appended with timestamp. And new empty file with initial name is created. | -| `gzip` | bool | yes | false | Whether to enable Gzip compression for backup log files. | -| `destination` | string | yes | stdout | Specify path for log output. Accepts log file path, or "stdout" and "stderr" reserved words to print in output streams. | +| `gzip` | bool | yes | false | Whether to enable Gzip compression to backup log files. | +| `destination` | string | yes | stdout | Specify path for log output. Accepts log file path, or "stdout" and "stderr" reserved words to print in output streams. File and folders are created if necessary. | +| `log_response` | bool | yes | true | Whether to attach response body to the log. | ### `cache` section diff --git a/internal/logs/logs.go b/internal/logs/logs.go index c2fc936..3a83b90 100644 --- a/internal/logs/logs.go +++ b/internal/logs/logs.go @@ -99,7 +99,7 @@ const ( FailedToPassAuthentication = "failed to pass authentication" // Error in ../../api/middleware/auth.go FailedToResolveCID = "failed to resolve CID" // Debug in ../../api/middleware/metrics.go RequestStart = "request start" // Info in ../../api/middleware/reqinfo.go - RequestHTTP = "http request" // Info in ../../api/middleware/log_http.go + LogHTTP = "http log" // Info in ../../api/middleware/log_http.go FailedToInitializeHTTPLogger = "failed to initialize http logger" // Warn in ../../api/middleware/log_http.go FailedToReloadHTTPFileLogger = "failed to reload http file logger" // Warn in ../../api/middleware/log_http.go FailedToGetRequestBody = "failed to get request body" // Warn in ../../api/middleware/log_http.go