From ec4ffaecf5848a204615bac275595cfcf4ab8872 Mon Sep 17 00:00:00 2001 From: Nikita Zinkevich Date: Tue, 16 Jul 2024 15:19:47 +0300 Subject: [PATCH] [#369] Write log to file Signed-off-by: Nikita Zinkevich Signed-off-by: Alex Vanin --- api/middleware/constants.go | 6 ++ api/middleware/log_http.go | 99 ++++++++++++++++++++++++++---- api/router.go | 8 ++- api/router_test.go | 1 + cmd/s3-gw/app.go | 23 ++++--- cmd/s3-gw/app_settings.go | 15 +++-- config/config.env | 11 ++++ config/config.yaml | 6 ++ docs/configuration.md | 22 +++++++ go.mod | 1 + go.sum | 2 + internal/logs/logs.go | 117 ++++++++++++++++++------------------ 12 files changed, 226 insertions(+), 85 deletions(-) diff --git a/api/middleware/constants.go b/api/middleware/constants.go index 5ef910c9..a93ba1cb 100644 --- a/api/middleware/constants.go +++ b/api/middleware/constants.go @@ -104,3 +104,9 @@ const ( PartNumberQuery = "partNumber" LegalHoldQuery = "legal-hold" ) + +const ( + StdoutPath = "stdout" + StderrPath = "stderr" + SinkName = "lumberjack" +) diff --git a/api/middleware/log_http.go b/api/middleware/log_http.go index ad1dd8a5..a097ea7a 100644 --- a/api/middleware/log_http.go +++ b/api/middleware/log_http.go @@ -1,27 +1,85 @@ package middleware import ( + "bytes" + "fmt" "io" "net/http" + "net/url" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs" "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "gopkg.in/natefinch/lumberjack.v2" ) -type LogHTTPSettings struct { - Enabled bool - MaxBody int64 +type LogHTTPConfig struct { + Enabled bool + MaxBody int64 + MaxLogSize int + OutputPath string + UseGzip bool +} + +// getFileLogger returns file logger for http requests or creates new if not exists. +func (h *LogHTTPConfig) getFileLogger() (*zap.Logger, error) { + c := newLoggerConfig() + c.OutputPaths = []string{h.OutputPath} + if h.OutputPath != StdoutPath && h.OutputPath != StderrPath && h.OutputPath != "" { + err := h.registerOutputSink() + if err != nil { + return nil, err + } + c.OutputPaths[0] = SinkName + ":" + h.OutputPath + } + + return c.Build() +} + +// registerOutputSink registers sink for logger file output. +func (h *LogHTTPConfig) registerOutputSink() error { + logRoller := &lumberjack.Logger{ + Filename: h.OutputPath, + MaxSize: h.MaxLogSize, + Compress: h.UseGzip, + } + err := zap.RegisterSink(SinkName, func(_ *url.URL) (zap.Sink, error) { + return lumberjackSink{ + Logger: logRoller, + }, nil + }) + if err != nil { + return err + } + + return nil +} + +type lumberjackSink struct { + *lumberjack.Logger +} + +func (lumberjackSink) Sync() error { + return nil } // LogHTTP logs http parameters from s3 request. -func LogHTTP(l *zap.Logger, settings LogHTTPSettings) Func { +func LogHTTP(l *zap.Logger, config *LogHTTPConfig) Func { + fileLogger, err := config.getFileLogger() + if err != nil { + return func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + h.ServeHTTP(w, r) + }) + } + } return func(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !settings.Enabled { + if !config.Enabled { h.ServeHTTP(w, r) return } - var httplog = l.With( + var httplog = fileLogger.With( zap.String("from", r.RemoteAddr), zap.String("URI", r.RequestURI), zap.String("method", r.Method), @@ -29,11 +87,11 @@ func LogHTTP(l *zap.Logger, settings LogHTTPSettings) Func { httplog = withFieldIfExist(httplog, "query", r.URL.Query()) httplog = withFieldIfExist(httplog, "headers", r.Header) - if r.ContentLength != 0 && r.ContentLength <= settings.MaxBody { + if r.ContentLength > 0 && r.ContentLength <= config.MaxBody { var err error httplog, err = withBody(httplog, r) if err != nil { - l.Error("read body error") + l.Error("read body error", zap.Error(err)) } } httplog.Info(logs.RequestHTTP) @@ -42,17 +100,34 @@ func LogHTTP(l *zap.Logger, settings LogHTTPSettings) Func { } } +// newLoggerConfig creates new zap.Config with disabled base fields. +func newLoggerConfig() zap.Config { + c := zap.NewProductionConfig() + c.DisableCaller = true + c.DisableStacktrace = true + c.EncoderConfig.MessageKey = zapcore.OmitKey + c.EncoderConfig.LevelKey = zapcore.OmitKey + c.EncoderConfig.TimeKey = zapcore.OmitKey + c.EncoderConfig.FunctionKey = zapcore.OmitKey + + return c +} + +// withBody reads body and attach it to log output. func withBody(httplog *zap.Logger, r *http.Request) (*zap.Logger, error) { - var body = make([]byte, r.ContentLength) - _, err := r.Body.Read(body) - if err != nil && err != io.EOF { - return nil, err + body, err := io.ReadAll(r.Body) + if err != nil { + return nil, fmt.Errorf("read body error: %w", err) } + defer r.Body.Close() + r.Body = io.NopCloser(bytes.NewBuffer(body)) + httplog = httplog.With(zap.String("body", string(body))) return httplog, nil } +// withFieldIfExist checks whether data is not empty and attach it to log output. func withFieldIfExist(log *zap.Logger, label string, data map[string][]string) *zap.Logger { if len(data) != 0 { log = log.With(zap.Any(label, data)) diff --git a/api/router.go b/api/router.go index a86e53b4..8fe3ebc4 100644 --- a/api/router.go +++ b/api/router.go @@ -108,7 +108,7 @@ type Config struct { Handler Handler Center s3middleware.Center Log *zap.Logger - LogHTTP s3middleware.LogHTTPSettings + LogHTTP *s3middleware.LogHTTPConfig Metrics *metrics.AppMetrics MiddlewareSettings Settings @@ -125,8 +125,12 @@ type Config struct { func NewRouter(cfg Config) *chi.Mux { api := chi.NewRouter() + + if cfg.LogHTTP.Enabled { + api.Use(s3middleware.LogHTTP(cfg.Log, cfg.LogHTTP)) + } + api.Use( - s3middleware.LogHTTP(cfg.Log, cfg.LogHTTP), s3middleware.Request(cfg.Log, cfg.MiddlewareSettings), middleware.ThrottleWithOpts(cfg.Throttle), middleware.Recoverer, diff --git a/api/router_test.go b/api/router_test.go index 49988bbe..04545f92 100644 --- a/api/router_test.go +++ b/api/router_test.go @@ -60,6 +60,7 @@ func prepareRouter(t *testing.T) *routerMock { Handler: &handlerMock{t: t, cfg: middlewareSettings, buckets: map[string]*data.BucketInfo{}}, Center: ¢erMock{t: t}, Log: logger, + LogHTTP: new(s3middleware.LogHTTPConfig), Metrics: metrics.NewAppMetrics(metricsConfig), MiddlewareSettings: middlewareSettings, PolicyChecker: policyChecker, diff --git a/cmd/s3-gw/app.go b/cmd/s3-gw/app.go index 24ff9933..804c83e1 100644 --- a/cmd/s3-gw/app.go +++ b/cmd/s3-gw/app.go @@ -87,8 +87,7 @@ type ( appSettings struct { logLevel zap.AtomicLevel - httpLoggingEnabled bool - maxHTTPLogBody int64 + httpLogging *s3middleware.LogHTTPConfig maxClient maxClientsConfig defaultMaxAge int notificatorEnabled bool @@ -209,12 +208,11 @@ func (a *App) initLayer(ctx context.Context) { func newAppSettings(log *Logger, v *viper.Viper, key *keys.PrivateKey) *appSettings { settings := &appSettings{ logLevel: log.lvl, + httpLogging: new(s3middleware.LogHTTPConfig), maxClient: newMaxClients(v), defaultMaxAge: fetchDefaultMaxAge(v, log.logger), notificatorEnabled: v.GetBool(cfgEnableNATS), frostfsidValidation: v.GetBool(cfgFrostfsIDValidationEnabled), - httpLoggingEnabled: v.GetBool(cfgLoggerRequestEnabled), - maxHTTPLogBody: v.GetInt64(cfgLoggerRequestMaxBody), } settings.resolveZoneList = v.GetStringSlice(cfgResolveBucketAllow) @@ -241,6 +239,7 @@ func (s *appSettings) update(v *viper.Viper, log *zap.Logger, key *keys.PrivateK s.setRetryMaxAttempts(fetchRetryMaxAttempts(v)) s.setRetryMaxBackoff(fetchRetryMaxBackoff(v)) s.setRetryStrategy(fetchRetryStrategy(v)) + s.updateHTTPLoggingSettings(v) } func (s *appSettings) updateNamespacesSettings(v *viper.Viper, log *zap.Logger) { @@ -610,6 +609,17 @@ func newMaxClients(cfg *viper.Viper) maxClientsConfig { return config } +func (s *appSettings) updateHTTPLoggingSettings(cfg *viper.Viper) { + s.mu.Lock() + defer s.mu.Unlock() + + s.httpLogging.Enabled = cfg.GetBool(cfgHTTPLoggingEnabled) + s.httpLogging.MaxBody = cfg.GetInt64(cfgHTTPLoggingMaxBody) + s.httpLogging.MaxLogSize = cfg.GetInt(cfgHTTPLoggingMaxLogSize) + s.httpLogging.OutputPath = cfg.GetString(cfgHTTPLoggingDestination) + s.httpLogging.UseGzip = cfg.GetBool(cfgHTTPLoggingGzip) +} + func getPools(ctx context.Context, logger *zap.Logger, cfg *viper.Viper) (*pool.Pool, *treepool.Pool, *keys.PrivateKey) { var prm pool.InitParameters var prmTree treepool.InitParameters @@ -731,10 +741,7 @@ func (a *App) Serve(ctx context.Context) { Handler: a.api, Center: a.ctr, Log: a.log, - LogHTTP: s3middleware.LogHTTPSettings{ - Enabled: a.settings.httpLoggingEnabled, - MaxBody: a.settings.maxHTTPLogBody, - }, + LogHTTP: a.settings.httpLogging, Metrics: a.metrics, Domains: domains, diff --git a/cmd/s3-gw/app_settings.go b/cmd/s3-gw/app_settings.go index a345f906..9bc4ef64 100644 --- a/cmd/s3-gw/app_settings.go +++ b/cmd/s3-gw/app_settings.go @@ -75,8 +75,12 @@ const ( // Settings. cfgLoggerLevel = "logger.level" cfgLoggerDestination = "logger.destination" - cfgLoggerRequestEnabled = "http_logging.enabled" - cfgLoggerRequestMaxBody = "http_logging.max_body" + // HttpLogging. + cfgHTTPLoggingEnabled = "http_logging.enabled" + cfgHTTPLoggingMaxBody = "http_logging.max_body" + cfgHTTPLoggingMaxLogSize = "http_logging.max_log_size" + cfgHTTPLoggingDestination = "http_logging.destination" + cfgHTTPLoggingGzip = "http_logging.gzip" // Wallet. cfgWalletPath = "wallet.path" @@ -743,8 +747,11 @@ func newSettings() *viper.Viper { v.SetDefault(cfgLoggerDestination, "stdout") // http logger - v.SetDefault(cfgLoggerRequestEnabled, false) - v.SetDefault(cfgLoggerRequestMaxBody, 1024) + v.SetDefault(cfgHTTPLoggingEnabled, false) + v.SetDefault(cfgHTTPLoggingMaxBody, 1024) + v.SetDefault(cfgHTTPLoggingMaxLogSize, 50) + v.SetDefault(cfgHTTPLoggingDestination, "stdout") + v.SetDefault(cfgHTTPLoggingGzip, false) // pool: v.SetDefault(cfgPoolErrorThreshold, defaultPoolErrorThreshold) diff --git a/config/config.env b/config/config.env index 8cfd6507..fada95ed 100644 --- a/config/config.env +++ b/config/config.env @@ -48,6 +48,17 @@ S3_GW_CONFIG=/path/to/config/yaml # Logger S3_GW_LOGGER_LEVEL=debug +# HTTP logger +S3_GW_HTTP_LOGGING_ENABLED=false +# max body size to log +S3_GW_HTTP_LOGGING_MAX_BODY=1024 +# max log size in Mb +S3_GW_HTTP_LOGGING_MAX_LOG_SIZE: 20 +# use log compression +S3_GW_HTTP_LOGGING_GZIP=true +# possible destination output values: filesystem path, url, "stdout", "stderr" +S3_GW_HTTP_LOGGING_DESTINATION=stdout + # RPC endpoint and order of resolving of bucket names S3_GW_RPC_ENDPOINT=http://morph-chain.frostfs.devenv:30333/ S3_GW_RESOLVE_ORDER="nns dns" diff --git a/config/config.yaml b/config/config.yaml index 7a9a11e8..be023c42 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -59,6 +59,12 @@ http_logging: enabled: false # max body size to log max_body: 1024 + # max log size in Mb + max_log_size: 20 + # use log compression + gzip: true + # possible output values: filesystem path, url, "stdout", "stderr" + destination: stdout # RPC endpoint and order of resolving of bucket names rpc_endpoint: http://morph-chain.frostfs.devenv:30333 diff --git a/docs/configuration.md b/docs/configuration.md index 72198478..b9c00e03 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -177,6 +177,7 @@ There are some custom types used for brevity: | `server` | [Server configuration](#server-section) | | `control` | [Control API configuration](#control-section) | | `logger` | [Logger configuration](#logger-section) | +| `http_logging` | [HTTP Request logger configuration](#http_logging-section) | | `cache` | [Cache configuration](#cache-section) | | `nats` | [NATS configuration](#nats-section) | | `cors` | [CORS configuration](#cors-section) | @@ -387,6 +388,27 @@ logger: | `level` | `string` | yes | `debug` | Logging level.
Possible values: `debug`, `info`, `warn`, `error`, `dpanic`, `panic`, `fatal`. | | `destination` | `string` | no | `stdout` | Destination for logger: `stdout` or `journald` | + +### `http_logging` section + +```yaml +http_logging: + enabled: false + max_body: 1024 + max_log_size: 20 + gzip: true + destination: stdout +``` + +| Parameter | Type | SIGHUP reload | Default value | Description | +|----------------|--------|---------------|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `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 | no | 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 | no | false | Whether to enable Gzip compression for backup log files. | +| `destination` | string | no | stdout | Specify path for log output. Accepts log file path, or "stdout" and "stderr" reserved words to print in output streams. | + + ### `cache` section ```yaml diff --git a/go.mod b/go.mod index 2df70f93..454468d8 100644 --- a/go.mod +++ b/go.mod @@ -33,6 +33,7 @@ require ( golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 google.golang.org/grpc v1.62.0 google.golang.org/protobuf v1.34.2 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) require ( diff --git a/go.sum b/go.sum index c2fa8a0c..2f06e63e 100644 --- a/go.sum +++ b/go.sum @@ -722,6 +722,8 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/logs/logs.go b/internal/logs/logs.go index ad2e3a57..c0930811 100644 --- a/internal/logs/logs.go +++ b/internal/logs/logs.go @@ -105,63 +105,62 @@ 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" - FailedToUnescapeObjectName = "failed to unescape object name" // Warn in ../../api/middleware/reqinfo.go - CouldNotHandleMessage = "could not handle message" // Error in ../../api/notifications/controller.go - CouldNotACKMessage = "could not ACK message" // Error in ../../api/notifications/controller.go - CouldntMarshalAnEvent = "couldn't marshal an event" // Error in ../../api/notifications/controller.go - CouldntSendAnEventToTopic = "couldn't send an event to topic" // Error in ../../api/notifications/controller.go - InvalidDefaultMaxAge = "invalid defaultMaxAge" // Fatal in ../../cmd/s3-gw/app_settings.go - CantShutDownService = "can't shut down service" // Panic in ../../cmd/s3-gw/service.go - CouldntGenerateRandomKey = "couldn't generate random key" // Fatal in ../../cmd/s3-gw/app.go - FailedToEnableNotifications = "failed to enable notifications" // Fatal in ../../cmd/s3-gw/app.go - CouldntInitializeLayer = "couldn't initialize layer" // Fatal in ../../cmd/s3-gw/app.go - FailedToCreateResolver = "failed to create resolver" // Fatal in ../../cmd/s3-gw/app.go - CouldNotLoadFrostFSPrivateKey = "could not load FrostFS private key" // Fatal in ../../cmd/s3-gw/app.go - FailedToCreateConnectionPool = "failed to create connection pool" // Fatal in ../../cmd/s3-gw/app.go - FailedToDialConnectionPool = "failed to dial connection pool" // Fatal in ../../cmd/s3-gw/app.go - FailedToCreateTreePool = "failed to create tree pool" // Fatal in ../../cmd/s3-gw/app.go - FailedToDialTreePool = "failed to dial tree pool" // Fatal in ../../cmd/s3-gw/app.go - ListenAndServe = "listen and serve" // Fatal in ../../cmd/s3-gw/app.go - NoHealthyServers = "no healthy servers" // Fatal in ../../cmd/s3-gw/app.go - CouldNotInitializeAPIHandler = "could not initialize API handler" // Fatal in ../../cmd/s3-gw/app.go - RuntimeSoftMemoryDefinedWithGOMEMLIMIT = "soft runtime memory defined with GOMEMLIMIT environment variable, config value skipped" // Warn in ../../cmd/s3-gw/app.go - RuntimeSoftMemoryLimitUpdated = "soft runtime memory limit value updated" // Info in ../../cmd/s3-gw/app.go - AnonRequestSkipFrostfsIDValidation = "anon request, skip FrostfsID validation" // Debug in ../../api/middleware/auth.go - FrostfsIDValidationFailed = "FrostfsID validation failed" // Error in ../../api/middleware/auth.go - InitFrostfsIDContractFailed = "init frostfsid contract failed" // Fatal in ../../cmd/s3-gw/app.go - InitPolicyContractFailed = "init policy contract failed" // Fatal in ../../cmd/s3-gw/app.go - ControlAPIHealthcheck = "healthcheck request" - ControlAPIPutPolicies = "put policies request" - ControlAPIRemovePolicies = "remove policies request" - ControlAPIGetPolicy = "get policy request" - ControlAPIListPolicies = "list policies request" - PolicyValidationFailed = "policy validation failed" - ParseTreeNode = "parse tree node" - FailedToGetRealObjectSize = "failed to get real object size" - CouldntDeleteObjectFromStorageContinueDeleting = "couldn't delete object from storage, continue deleting from tree" - CouldntPutAccessBoxIntoCache = "couldn't put accessbox into cache" - InvalidAccessBoxCacheRemovingCheckInterval = "invalid accessbox check removing interval, using default value" - CouldNotCloseRequestBody = "could not close request body" - BucketOwnerKeyIsMissing = "bucket owner key is missing" - SettingsNodeInvalidOwnerKey = "settings node: invalid owner key" - SuccessfulAuth = "successful auth" - PolicyRequest = "policy request" - FailedToGenerateRequestID = "failed to generate request id" - InvalidBucketObjectLockEnabledHeader = "invalid X-Amz-Bucket-Object-Lock-Enabled header" - InvalidTreeKV = "invalid tree service meta KV" - FailedToWriteResponse = "failed to write response" - PolicyCouldntBeConvertedToNativeRules = "policy couldn't be converted to native rules, only s3 rules be applied" - CouldntCacheSubject = "couldn't cache subject info" - UserGroupsListIsEmpty = "user groups list is empty, subject not found" - CouldntCacheUserKey = "couldn't cache user key" - FoundSeveralBucketCorsNodes = "found several bucket cors nodes, latest be used" - FoundSeveralNotificationConfigurationNodes = "found several notification configuration nodes, latest be used" - FoundSeveralObjectTaggingNodes = "found several object tagging nodes, latest be used" - FoundSeveralBucketTaggingNodes = "found several bucket tagging nodes, latest be used" - FoundSeveralBucketSettingsNodes = "found several bucket settings nodes, latest be used" - UnexpectedMultiNodeIDsInSubTreeMultiParts = "unexpected multi node ids in sub tree multi parts" - FoundSeveralSystemNodes = "found several system nodes, latest be used" - FailedToParsePartInfo = "failed to parse part info" + RequestHTTP = "http request" + FailedToUnescapeObjectName = "failed to unescape object name" // Warn in ../../api/middleware/reqinfo.go + CouldNotHandleMessage = "could not handle message" // Error in ../../api/notifications/controller.go + CouldNotACKMessage = "could not ACK message" // Error in ../../api/notifications/controller.go + CouldntMarshalAnEvent = "couldn't marshal an event" // Error in ../../api/notifications/controller.go + CouldntSendAnEventToTopic = "couldn't send an event to topic" // Error in ../../api/notifications/controller.go + InvalidDefaultMaxAge = "invalid defaultMaxAge" // Fatal in ../../cmd/s3-gw/app_settings.go + CantShutDownService = "can't shut down service" // Panic in ../../cmd/s3-gw/service.go + CouldntGenerateRandomKey = "couldn't generate random key" // Fatal in ../../cmd/s3-gw/app.go + FailedToEnableNotifications = "failed to enable notifications" // Fatal in ../../cmd/s3-gw/app.go + CouldntInitializeLayer = "couldn't initialize layer" // Fatal in ../../cmd/s3-gw/app.go + FailedToCreateResolver = "failed to create resolver" // Fatal in ../../cmd/s3-gw/app.go + CouldNotLoadFrostFSPrivateKey = "could not load FrostFS private key" // Fatal in ../../cmd/s3-gw/app.go + FailedToCreateConnectionPool = "failed to create connection pool" // Fatal in ../../cmd/s3-gw/app.go + FailedToDialConnectionPool = "failed to dial connection pool" // Fatal in ../../cmd/s3-gw/app.go + FailedToCreateTreePool = "failed to create tree pool" // Fatal in ../../cmd/s3-gw/app.go + FailedToDialTreePool = "failed to dial tree pool" // Fatal in ../../cmd/s3-gw/app.go + ListenAndServe = "listen and serve" // Fatal in ../../cmd/s3-gw/app.go + NoHealthyServers = "no healthy servers" // Fatal in ../../cmd/s3-gw/app.go + CouldNotInitializeAPIHandler = "could not initialize API handler" // Fatal in ../../cmd/s3-gw/app.go + RuntimeSoftMemoryDefinedWithGOMEMLIMIT = "soft runtime memory defined with GOMEMLIMIT environment variable, config value skipped" // Warn in ../../cmd/s3-gw/app.go + RuntimeSoftMemoryLimitUpdated = "soft runtime memory limit value updated" // Info in ../../cmd/s3-gw/app.go + AnonRequestSkipFrostfsIDValidation = "anon request, skip FrostfsID validation" // Debug in ../../api/middleware/auth.go + FrostfsIDValidationFailed = "FrostfsID validation failed" // Error in ../../api/middleware/auth.go + InitFrostfsIDContractFailed = "init frostfsid contract failed" // Fatal in ../../cmd/s3-gw/app.go + InitPolicyContractFailed = "init policy contract failed" // Fatal in ../../cmd/s3-gw/app.go + ControlAPIHealthcheck = "healthcheck request" + ControlAPIPutPolicies = "put policies request" + ControlAPIRemovePolicies = "remove policies request" + ControlAPIGetPolicy = "get policy request" + ControlAPIListPolicies = "list policies request" + PolicyValidationFailed = "policy validation failed" + ParseTreeNode = "parse tree node" + FailedToGetRealObjectSize = "failed to get real object size" + CouldntDeleteObjectFromStorageContinueDeleting = "couldn't delete object from storage, continue deleting from tree" + CouldntPutAccessBoxIntoCache = "couldn't put accessbox into cache" + InvalidAccessBoxCacheRemovingCheckInterval = "invalid accessbox check removing interval, using default value" + CouldNotCloseRequestBody = "could not close request body" + BucketOwnerKeyIsMissing = "bucket owner key is missing" + SettingsNodeInvalidOwnerKey = "settings node: invalid owner key" + SuccessfulAuth = "successful auth" + PolicyRequest = "policy request" + FailedToGenerateRequestID = "failed to generate request id" + InvalidBucketObjectLockEnabledHeader = "invalid X-Amz-Bucket-Object-Lock-Enabled header" + InvalidTreeKV = "invalid tree service meta KV" + FailedToWriteResponse = "failed to write response" + PolicyCouldntBeConvertedToNativeRules = "policy couldn't be converted to native rules, only s3 rules be applied" + CouldntCacheSubject = "couldn't cache subject info" + UserGroupsListIsEmpty = "user groups list is empty, subject not found" + CouldntCacheUserKey = "couldn't cache user key" + FoundSeveralBucketCorsNodes = "found several bucket cors nodes, latest be used" + FoundSeveralNotificationConfigurationNodes = "found several notification configuration nodes, latest be used" + FoundSeveralObjectTaggingNodes = "found several object tagging nodes, latest be used" + FoundSeveralBucketTaggingNodes = "found several bucket tagging nodes, latest be used" + FoundSeveralBucketSettingsNodes = "found several bucket settings nodes, latest be used" + UnexpectedMultiNodeIDsInSubTreeMultiParts = "unexpected multi node ids in sub tree multi parts" + FoundSeveralSystemNodes = "found several system nodes, latest be used" + FailedToParsePartInfo = "failed to parse part info" )