[#148] Add trace_id to logs #152
|
@ -3,7 +3,10 @@
|
||||||
This document outlines major changes between releases.
|
This document outlines major changes between releases.
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
- Support percent-encoding for GET queries (#134)
|
- Support percent-encoding for GET queries (#134)
|
||||||
|
- Add `trace_id` to logs (#148)
|
||||||
dkirillov marked this conversation as resolved
Outdated
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Update go version to 1.22 (#132)
|
- Update go version to 1.22 (#132)
|
||||||
|
|
|
@ -42,6 +42,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
@ -589,15 +590,15 @@ func (a *app) configureRouter(handler *handler.Handler) {
|
||||||
response.Error(r, "Method Not Allowed", fasthttp.StatusMethodNotAllowed)
|
response.Error(r, "Method Not Allowed", fasthttp.StatusMethodNotAllowed)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.POST("/upload/{cid}", a.logger(a.canonicalizer(a.tokenizer(a.tracer(a.reqNamespace(handler.Upload))))))
|
r.POST("/upload/{cid}", a.tracer(a.logger(a.canonicalizer(a.tokenizer(a.reqNamespace(handler.Upload))))))
|
||||||
a.log.Info(logs.AddedPathUploadCid)
|
a.log.Info(logs.AddedPathUploadCid)
|
||||||
r.GET("/get/{cid}/{oid:*}", a.logger(a.canonicalizer(a.tokenizer(a.tracer(a.reqNamespace(handler.DownloadByAddressOrBucketName))))))
|
r.GET("/get/{cid}/{oid:*}", a.tracer(a.logger(a.canonicalizer(a.tokenizer(a.reqNamespace(handler.DownloadByAddressOrBucketName))))))
|
||||||
r.HEAD("/get/{cid}/{oid:*}", a.logger(a.canonicalizer(a.tokenizer(a.tracer(a.reqNamespace(handler.HeadByAddressOrBucketName))))))
|
r.HEAD("/get/{cid}/{oid:*}", a.tracer(a.logger(a.canonicalizer(a.tokenizer(a.reqNamespace(handler.HeadByAddressOrBucketName))))))
|
||||||
a.log.Info(logs.AddedPathGetCidOid)
|
a.log.Info(logs.AddedPathGetCidOid)
|
||||||
r.GET("/get_by_attribute/{cid}/{attr_key}/{attr_val:*}", a.logger(a.canonicalizer(a.tokenizer(a.tracer(a.reqNamespace(handler.DownloadByAttribute))))))
|
r.GET("/get_by_attribute/{cid}/{attr_key}/{attr_val:*}", a.tracer(a.logger(a.canonicalizer(a.tokenizer(a.reqNamespace(handler.DownloadByAttribute))))))
|
||||||
r.HEAD("/get_by_attribute/{cid}/{attr_key}/{attr_val:*}", a.logger(a.canonicalizer(a.tokenizer(a.tracer(a.reqNamespace(handler.HeadByAttribute))))))
|
r.HEAD("/get_by_attribute/{cid}/{attr_key}/{attr_val:*}", a.tracer(a.logger(a.canonicalizer(a.tokenizer(a.reqNamespace(handler.HeadByAttribute))))))
|
||||||
a.log.Info(logs.AddedPathGetByAttributeCidAttrKeyAttrVal)
|
a.log.Info(logs.AddedPathGetByAttributeCidAttrKeyAttrVal)
|
||||||
r.GET("/zip/{cid}/{prefix:*}", a.logger(a.canonicalizer(a.tokenizer(a.tracer(a.reqNamespace(handler.DownloadZipped))))))
|
r.GET("/zip/{cid}/{prefix:*}", a.tracer(a.logger(a.canonicalizer(a.tokenizer(a.reqNamespace(handler.DownloadZipped))))))
|
||||||
a.log.Info(logs.AddedPathZipCidPrefix)
|
a.log.Info(logs.AddedPathZipCidPrefix)
|
||||||
|
|
||||||
a.webServer.Handler = r.Handler
|
a.webServer.Handler = r.Handler
|
||||||
|
@ -605,11 +606,24 @@ func (a *app) configureRouter(handler *handler.Handler) {
|
||||||
|
|
||||||
func (a *app) logger(h fasthttp.RequestHandler) fasthttp.RequestHandler {
|
func (a *app) logger(h fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||||
return func(req *fasthttp.RequestCtx) {
|
return func(req *fasthttp.RequestCtx) {
|
||||||
a.log.Info(logs.Request, zap.String("remote", req.RemoteAddr().String()),
|
requiredFields := []zap.Field{zap.Uint64("id", req.ID())}
|
||||||
|
reqCtx := utils.GetContextFromRequest(req)
|
||||||
|
if traceID := trace.SpanFromContext(reqCtx).SpanContext().TraceID(); traceID.IsValid() {
|
||||||
|
requiredFields = append(requiredFields, zap.String("trace_id", traceID.String()))
|
||||||
|
}
|
||||||
|
log := a.log.With(requiredFields...)
|
||||||
|
|
||||||
|
reqCtx = utils.SetReqLog(reqCtx, log)
|
||||||
|
utils.SetContextToRequest(reqCtx, req)
|
||||||
|
|
||||||
|
fields := []zap.Field{
|
||||||
|
zap.String("remote", req.RemoteAddr().String()),
|
||||||
dkirillov marked this conversation as resolved
Outdated
dkirillov
commented
Consider something like this
Consider something like this
```diff
diff --git a/cmd/http-gw/app.go b/cmd/http-gw/app.go
index 007a8d7..de01f75 100644
--- a/cmd/http-gw/app.go
+++ b/cmd/http-gw/app.go
@@ -607,20 +607,24 @@ func (a *app) configureRouter(handler *handler.Handler) {
func (a *app) logger(h fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(req *fasthttp.RequestCtx) {
+ requiredFields := []zap.Field{zap.Uint64("id", req.ID())}
+ reqCtx := utils.GetContextFromRequest(req)
+ if traceID := trace.SpanFromContext(reqCtx).SpanContext().TraceID(); traceID.IsValid() {
+ requiredFields = append(requiredFields, zap.String("trace_id", traceID.String()))
+ }
+ log := a.log.With(requiredFields...)
+
+ reqCtx = utils.SetReqLog(reqCtx, log)
+ utils.SetContextToRequest(reqCtx, req)
+
fields := []zap.Field{
zap.String("remote", req.RemoteAddr().String()),
zap.ByteString("method", req.Method()),
zap.ByteString("path", req.Path()),
zap.ByteString("query", req.QueryArgs().QueryString()),
- zap.Uint64("id", req.ID()),
}
- appCtx := utils.GetContextFromRequest(req)
- if traceID := trace.SpanFromContext(appCtx).SpanContext().TraceID(); traceID.IsValid() {
- fields = append(fields, zap.String("trace_id", traceID.String()))
- }
-
- a.log.Info(logs.Request, fields...)
+ log.Info(logs.Request, fields...)
h(req)
}
}
@@ -659,19 +663,17 @@ func (a *app) canonicalizer(h fasthttp.RequestHandler) fasthttp.RequestHandler {
func (a *app) tokenizer(h fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(req *fasthttp.RequestCtx) {
- appCtx, err := tokens.StoreBearerTokenAppCtx(utils.GetContextFromRequest(req), req)
+ reqCtx := utils.GetContextFromRequest(req)
+
+ appCtx, err := tokens.StoreBearerTokenAppCtx(reqCtx, req)
if err != nil {
fields := []zap.Field{
zap.Uint64("id", req.ID()),
zap.Error(err),
}
- reqCtx := utils.GetContextFromRequest(req)
- if traceID := trace.SpanFromContext(reqCtx).SpanContext().TraceID(); traceID.IsValid() {
- fields = append(fields, zap.String("trace_id", traceID.String()))
- }
-
- a.log.Error(logs.CouldNotFetchAndStoreBearerToken, fields...)
+ log := utils.GetReqLogOrDefault(reqCtx, a.log)
+ log.Error(logs.CouldNotFetchAndStoreBearerToken, fields...)
response.Error(req, "could not fetch and store bearer token: "+err.Error(), fasthttp.StatusBadRequest)
return
}
diff --git a/utils/util.go b/utils/util.go
index d513817..dd00d38 100644
--- a/utils/util.go
+++ b/utils/util.go
@@ -4,6 +4,7 @@ import (
"context"
"github.com/valyala/fasthttp"
+ "go.uber.org/zap"
)
// SetContextToRequest adds new context to fasthttp request.
@@ -15,3 +16,29 @@ func SetContextToRequest(ctx context.Context, c *fasthttp.RequestCtx) {
func GetContextFromRequest(c *fasthttp.RequestCtx) context.Context {
return c.UserValue("context").(context.Context)
}
+
+type ctxReqLoggerKeyType struct{}
+
+func SetReqLog(ctx context.Context, log *zap.Logger) context.Context {
+ if ctx == nil {
+ return nil
+ }
+ return context.WithValue(ctx, ctxReqLoggerKeyType{}, log)
+}
+
+func GetReqLog(ctx context.Context) *zap.Logger {
+ if ctx == nil {
+ return nil
+ } else if r, ok := ctx.Value(ctxReqLoggerKeyType{}).(*zap.Logger); ok {
+ return r
+ }
+ return nil
+}
+
+func GetReqLogOrDefault(ctx context.Context, defaultLog *zap.Logger) *zap.Logger {
+ log := GetReqLog(ctx)
+ if log == nil {
+ log = defaultLog
+ }
+ return log
+}
```
|
|||||||
zap.ByteString("method", req.Method()),
|
zap.ByteString("method", req.Method()),
|
||||||
zap.ByteString("path", req.Path()),
|
zap.ByteString("path", req.Path()),
|
||||||
zap.ByteString("query", req.QueryArgs().QueryString()),
|
zap.ByteString("query", req.QueryArgs().QueryString()),
|
||||||
zap.Uint64("id", req.ID()))
|
}
|
||||||
|
|
||||||
|
log.Info(logs.Request, fields...)
|
||||||
h(req)
|
h(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -648,9 +662,12 @@ func (a *app) canonicalizer(h fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||||
|
|
||||||
nzinkevich
commented
Are there any reasons why we refused getting ctx from Are there any reasons why we refused getting ctx from `a.ctx`? If so, let's replace with `reqCtx`
r.loginov
commented
The reason is that the first middleware that works with context should get context based on The reason is that the first middleware that works with context should get context based on `appCtx`. Previously, the middleware `tokenizer` was the first handler that featured context, and that's why it didn't use the request context, but used the application context. However, now the first middleware that works with context is `tracer`. Therefore, `tracer` gets the context from `appCtx`, and at the same time `tokenizer` no longer needs to take the context from `appCtx` because the necessary information for it will be in the context of the request.
In other words, we want to store the data that is inherent in a specific request (trace information, bearer token) in the context of the request. And we want to make the request context based on the application context.
If I'm wrong or didn't answer the question, let me know.
This comment responds to two comments.
dkirillov
commented
It seems we can write
This can help don't get again context in line 669 It seems we can write
```golang
reqCtx := utils.GetContextFromRequest(req)
appCtx, err := tokens.StoreBearerTokenAppCtx(reqCtx, req)
```
This can help don't get again context in line 669
|
|||||||
func (a *app) tokenizer(h fasthttp.RequestHandler) fasthttp.RequestHandler {
|
func (a *app) tokenizer(h fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||||
return func(req *fasthttp.RequestCtx) {
|
return func(req *fasthttp.RequestCtx) {
|
||||||
appCtx, err := tokens.StoreBearerTokenAppCtx(a.ctx, req)
|
reqCtx := utils.GetContextFromRequest(req)
|
||||||
|
appCtx, err := tokens.StoreBearerTokenAppCtx(reqCtx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.log.Error(logs.CouldNotFetchAndStoreBearerToken, zap.Uint64("id", req.ID()), zap.Error(err))
|
log := utils.GetReqLogOrDefault(reqCtx, a.log)
|
||||||
|
|
||||||
|
log.Error(logs.CouldNotFetchAndStoreBearerToken, zap.Error(err))
|
||||||
response.Error(req, "could not fetch and store bearer token: "+err.Error(), fasthttp.StatusBadRequest)
|
response.Error(req, "could not fetch and store bearer token: "+err.Error(), fasthttp.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -661,9 +678,7 @@ func (a *app) tokenizer(h fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||||
|
|
||||||
func (a *app) tracer(h fasthttp.RequestHandler) fasthttp.RequestHandler {
|
func (a *app) tracer(h fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||||
return func(req *fasthttp.RequestCtx) {
|
return func(req *fasthttp.RequestCtx) {
|
||||||
appCtx := utils.GetContextFromRequest(req)
|
appCtx, span := utils.StartHTTPServerSpan(a.ctx, req, "REQUEST")
|
||||||
|
|
||||||
appCtx, span := utils.StartHTTPServerSpan(appCtx, req, "REQUEST")
|
|
||||||
defer func() {
|
defer func() {
|
||||||
utils.SetHTTPTraceInfo(appCtx, span, req)
|
utils.SetHTTPTraceInfo(appCtx, span, req)
|
||||||
span.End()
|
span.End()
|
||||||
|
|
|
@ -113,8 +113,10 @@ func urlencode(prefix, filename string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) browseObjects(c *fasthttp.RequestCtx, bucketInfo *data.BucketInfo, prefix string) {
|
func (h *Handler) browseObjects(c *fasthttp.RequestCtx, bucketInfo *data.BucketInfo, prefix string) {
|
||||||
log := h.log.With(zap.String("bucket", bucketInfo.Name))
|
|
||||||
ctx := utils.GetContextFromRequest(c)
|
ctx := utils.GetContextFromRequest(c)
|
||||||
|
reqLog := utils.GetReqLogOrDefault(ctx, h.log)
|
||||||
|
log := reqLog.With(zap.String("bucket", bucketInfo.Name))
|
||||||
|
|
||||||
dkirillov marked this conversation as resolved
Outdated
dkirillov
commented
Why don't we write
? Why don't we write
```golang
ctx := utils.GetContextFromRequest(c)
reqLog := utils.GetReqLogOrDefault(ctx, h.log)
log := reqLog.With(zap.String("bucket", bucketInfo.Name))
```
?
|
|||||||
nodes, err := h.listObjects(ctx, bucketInfo, prefix)
|
nodes, err := h.listObjects(ctx, bucketInfo, prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logAndSendBucketError(c, log, err)
|
logAndSendBucketError(c, log, err)
|
||||||
nzinkevich
commented
I think we can extract these repeating conditions to a separate function - it occurs 8 times I think we can extract these repeating conditions to a separate function - it occurs 8 times
r.loginov
commented
done
done
I also thought about using this version of the function, but it didn't seem very flexible to me. What do you think?
```
func WithCustomFields(ctx context.Context, log *zap.Logger, fields ...zap.Field) *zap.Logger {
if traceID := trace.SpanFromContext(ctx).SpanContext().TraceID(); traceID.IsValid() {
fields = append(fields, zap.String("trace_id", traceID.String()))
}
return log.With(fields...)
}
```
|
|||||||
|
|
|
@ -84,16 +84,17 @@ func (h *Handler) DownloadZipped(c *fasthttp.RequestCtx) {
|
||||||
scid, _ := c.UserValue("cid").(string)
|
scid, _ := c.UserValue("cid").(string)
|
||||||
prefix, _ := c.UserValue("prefix").(string)
|
prefix, _ := c.UserValue("prefix").(string)
|
||||||
|
|
||||||
|
ctx := utils.GetContextFromRequest(c)
|
||||||
|
log := utils.GetReqLogOrDefault(ctx, h.log)
|
||||||
dkirillov marked this conversation as resolved
Outdated
dkirillov
commented
The same as previous comment The same as previous comment
|
|||||||
|
|
||||||
prefix, err := url.QueryUnescape(prefix)
|
prefix, err := url.QueryUnescape(prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.log.Error(logs.FailedToUnescapeQuery, zap.String("cid", scid), zap.String("prefix", prefix), zap.Uint64("id", c.ID()), zap.Error(err))
|
log.Error(logs.FailedToUnescapeQuery, zap.String("cid", scid), zap.String("prefix", prefix), zap.Error(err))
|
||||||
response.Error(c, "could not unescape prefix: "+err.Error(), fasthttp.StatusBadRequest)
|
response.Error(c, "could not unescape prefix: "+err.Error(), fasthttp.StatusBadRequest)
|
||||||
dkirillov marked this conversation as resolved
Outdated
dkirillov
commented
I suppose we can skip additional adding id to log because we use logger from context
I suppose we can skip additional adding id to log because we use logger from context
```golang
log.Error(logs.FailedToUnescapeQuery, zap.String("cid", scid), zap.String("prefix", prefix), zap.Error(err))
```
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log := h.log.With(zap.String("cid", scid), zap.String("prefix", prefix), zap.Uint64("id", c.ID()))
|
log = log.With(zap.String("cid", scid), zap.String("prefix", prefix))
|
||||||
|
|
||||||
ctx := utils.GetContextFromRequest(c)
|
|
||||||
|
|
||||||
dkirillov marked this conversation as resolved
Outdated
dkirillov
commented
The same
The same
```golang
log = log.With(zap.String("cid", scid), zap.String("prefix", prefix)
```
|
|||||||
bktInfo, err := h.getBucketInfo(ctx, scid, log)
|
bktInfo, err := h.getBucketInfo(ctx, scid, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -190,13 +190,12 @@ func New(params *AppParams, config Config, tree *tree.Tree) *Handler {
|
||||||
// byAddress is a wrapper for function (e.g. request.headObject, request.receiveFile) that
|
// byAddress is a wrapper for function (e.g. request.headObject, request.receiveFile) that
|
||||||
// prepares request and object address to it.
|
// prepares request and object address to it.
|
||||||
func (h *Handler) byAddress(c *fasthttp.RequestCtx, f func(context.Context, request, oid.Address)) {
|
func (h *Handler) byAddress(c *fasthttp.RequestCtx, f func(context.Context, request, oid.Address)) {
|
||||||
var (
|
idCnr, _ := c.UserValue("cid").(string)
|
||||||
idCnr, _ = c.UserValue("cid").(string)
|
idObj, _ := c.UserValue("oid").(string)
|
||||||
idObj, _ = c.UserValue("oid").(string)
|
|
||||||
log = h.log.With(zap.String("cid", idCnr), zap.String("oid", idObj))
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx := utils.GetContextFromRequest(c)
|
ctx := utils.GetContextFromRequest(c)
|
||||||
|
reqLog := utils.GetReqLogOrDefault(ctx, h.log)
|
||||||
|
log := reqLog.With(zap.String("cid", idCnr), zap.String("oid", idObj))
|
||||||
|
|
||||||
bktInfo, err := h.getBucketInfo(ctx, idCnr, log)
|
bktInfo, err := h.getBucketInfo(ctx, idCnr, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -219,12 +218,13 @@ func (h *Handler) byAddress(c *fasthttp.RequestCtx, f func(context.Context, requ
|
||||||
// byObjectName is a wrapper for function (e.g. request.headObject, request.receiveFile) that
|
// byObjectName is a wrapper for function (e.g. request.headObject, request.receiveFile) that
|
||||||
// prepares request and object address to it.
|
// prepares request and object address to it.
|
||||||
func (h *Handler) byObjectName(c *fasthttp.RequestCtx, f func(context.Context, request, oid.Address)) {
|
func (h *Handler) byObjectName(c *fasthttp.RequestCtx, f func(context.Context, request, oid.Address)) {
|
||||||
var (
|
bucketname := c.UserValue("cid").(string)
|
||||||
bucketname = c.UserValue("cid").(string)
|
key := c.UserValue("oid").(string)
|
||||||
key = c.UserValue("oid").(string)
|
download := c.QueryArgs().GetBool("download")
|
||||||
log = h.log.With(zap.String("bucketname", bucketname), zap.String("key", key))
|
|
||||||
download = c.QueryArgs().GetBool("download")
|
ctx := utils.GetContextFromRequest(c)
|
||||||
)
|
reqLog := utils.GetReqLogOrDefault(ctx, h.log)
|
||||||
|
log := reqLog.With(zap.String("bucketname", bucketname), zap.String("key", key))
|
||||||
|
|
||||||
unescapedKey, err := url.QueryUnescape(key)
|
unescapedKey, err := url.QueryUnescape(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -232,8 +232,6 @@ func (h *Handler) byObjectName(c *fasthttp.RequestCtx, f func(context.Context, r
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := utils.GetContextFromRequest(c)
|
|
||||||
|
|
||||||
bktInfo, err := h.getBucketInfo(ctx, bucketname, log)
|
bktInfo, err := h.getBucketInfo(ctx, bucketname, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logAndSendBucketError(c, log, err)
|
logAndSendBucketError(c, log, err)
|
||||||
|
@ -275,23 +273,24 @@ func (h *Handler) byAttribute(c *fasthttp.RequestCtx, f func(context.Context, re
|
||||||
key, _ := c.UserValue("attr_key").(string)
|
key, _ := c.UserValue("attr_key").(string)
|
||||||
val, _ := c.UserValue("attr_val").(string)
|
val, _ := c.UserValue("attr_val").(string)
|
||||||
|
|
||||||
|
ctx := utils.GetContextFromRequest(c)
|
||||||
|
log := utils.GetReqLogOrDefault(ctx, h.log)
|
||||||
|
|
||||||
key, err := url.QueryUnescape(key)
|
key, err := url.QueryUnescape(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.log.Error(logs.FailedToUnescapeQuery, zap.String("cid", scid), zap.String("attr_key", key), zap.Uint64("id", c.ID()), zap.Error(err))
|
log.Error(logs.FailedToUnescapeQuery, zap.String("cid", scid), zap.String("attr_key", key), zap.Error(err))
|
||||||
response.Error(c, "could not unescape attr_key: "+err.Error(), fasthttp.StatusBadRequest)
|
response.Error(c, "could not unescape attr_key: "+err.Error(), fasthttp.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val, err = url.QueryUnescape(val)
|
val, err = url.QueryUnescape(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.log.Error(logs.FailedToUnescapeQuery, zap.String("cid", scid), zap.String("attr_val", val), zap.Uint64("id", c.ID()), zap.Error(err))
|
log.Error(logs.FailedToUnescapeQuery, zap.String("cid", scid), zap.String("attr_val", val), zap.Error(err))
|
||||||
response.Error(c, "could not unescape attr_val: "+err.Error(), fasthttp.StatusBadRequest)
|
response.Error(c, "could not unescape attr_val: "+err.Error(), fasthttp.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log := h.log.With(zap.String("cid", scid), zap.String("attr_key", key), zap.String("attr_val", val))
|
log = log.With(zap.String("cid", scid), zap.String("attr_key", key), zap.String("attr_val", val))
|
||||||
|
|
||||||
ctx := utils.GetContextFromRequest(c)
|
|
||||||
|
|
||||||
bktInfo, err := h.getBucketInfo(ctx, scid, log)
|
bktInfo, err := h.getBucketInfo(ctx, scid, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -48,13 +48,15 @@ func (h *Handler) Upload(c *fasthttp.RequestCtx) {
|
||||||
file MultipartFile
|
file MultipartFile
|
||||||
idObj oid.ID
|
idObj oid.ID
|
||||||
addr oid.Address
|
addr oid.Address
|
||||||
scid, _ = c.UserValue("cid").(string)
|
|
||||||
log = h.log.With(zap.String("cid", scid))
|
|
||||||
bodyStream = c.RequestBodyStream()
|
|
||||||
drainBuf = make([]byte, drainBufSize)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
scid, _ := c.UserValue("cid").(string)
|
||||||
|
bodyStream := c.RequestBodyStream()
|
||||||
|
drainBuf := make([]byte, drainBufSize)
|
||||||
|
|
||||||
ctx := utils.GetContextFromRequest(c)
|
ctx := utils.GetContextFromRequest(c)
|
||||||
|
reqLog := utils.GetReqLogOrDefault(ctx, h.log)
|
||||||
|
log := reqLog.With(zap.String("cid", scid))
|
||||||
|
|
||||||
bktInfo, err := h.getBucketInfo(ctx, scid, log)
|
bktInfo, err := h.getBucketInfo(ctx, scid, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -75,13 +77,15 @@ func (h *Handler) Upload(c *fasthttp.RequestCtx) {
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
)
|
)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
boundary := string(c.Request.Header.MultipartFormBoundary())
|
boundary := string(c.Request.Header.MultipartFormBoundary())
|
||||||
if file, err = fetchMultipartFile(h.log, bodyStream, boundary); err != nil {
|
if file, err = fetchMultipartFile(log, bodyStream, boundary); err != nil {
|
||||||
log.Error(logs.CouldNotReceiveMultipartForm, zap.Error(err))
|
log.Error(logs.CouldNotReceiveMultipartForm, zap.Error(err))
|
||||||
response.Error(c, "could not receive multipart/form: "+err.Error(), fasthttp.StatusBadRequest)
|
response.Error(c, "could not receive multipart/form: "+err.Error(), fasthttp.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
filtered, err := filterHeaders(h.log, &c.Request.Header)
|
|
||||||
|
filtered, err := filterHeaders(log, &c.Request.Header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(logs.CouldNotProcessHeaders, zap.Error(err))
|
log.Error(logs.CouldNotProcessHeaders, zap.Error(err))
|
||||||
response.Error(c, err.Error(), fasthttp.StatusBadRequest)
|
response.Error(c, err.Error(), fasthttp.StatusBadRequest)
|
||||||
|
@ -143,7 +147,7 @@ func (h *Handler) Upload(c *fasthttp.RequestCtx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if idObj, err = h.frostfs.CreateObject(ctx, prm); err != nil {
|
if idObj, err = h.frostfs.CreateObject(ctx, prm); err != nil {
|
||||||
h.handlePutFrostFSErr(c, err)
|
h.handlePutFrostFSErr(c, err, log)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,11 +178,11 @@ func (h *Handler) Upload(c *fasthttp.RequestCtx) {
|
||||||
c.Response.Header.SetContentType(jsonHeader)
|
c.Response.Header.SetContentType(jsonHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) handlePutFrostFSErr(r *fasthttp.RequestCtx, err error) {
|
func (h *Handler) handlePutFrostFSErr(r *fasthttp.RequestCtx, err error, log *zap.Logger) {
|
||||||
statusCode, msg, additionalFields := response.FormErrorResponse("could not store file in frostfs", err)
|
statusCode, msg, additionalFields := response.FormErrorResponse("could not store file in frostfs", err)
|
||||||
logFields := append([]zap.Field{zap.Error(err)}, additionalFields...)
|
logFields := append([]zap.Field{zap.Error(err)}, additionalFields...)
|
||||||
|
|
||||||
h.log.Error(logs.CouldNotStoreFileInFrostfs, logFields...)
|
log.Error(logs.CouldNotStoreFileInFrostfs, logFields...)
|
||||||
response.Error(r, msg, statusCode)
|
response.Error(r, msg, statusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetContextToRequest adds new context to fasthttp request.
|
// SetContextToRequest adds new context to fasthttp request.
|
||||||
|
@ -15,3 +16,34 @@ func SetContextToRequest(ctx context.Context, c *fasthttp.RequestCtx) {
|
||||||
func GetContextFromRequest(c *fasthttp.RequestCtx) context.Context {
|
func GetContextFromRequest(c *fasthttp.RequestCtx) context.Context {
|
||||||
return c.UserValue("context").(context.Context)
|
return c.UserValue("context").(context.Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ctxReqLoggerKeyType struct{}
|
||||||
|
|
||||||
|
// SetReqLog sets child zap.Logger in the context.
|
||||||
|
func SetReqLog(ctx context.Context, log *zap.Logger) context.Context {
|
||||||
|
if ctx == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return context.WithValue(ctx, ctxReqLoggerKeyType{}, log)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetReqLog returns log if set.
|
||||||
|
// If zap.Logger isn't set returns nil.
|
||||||
|
func GetReqLog(ctx context.Context) *zap.Logger {
|
||||||
|
if ctx == nil {
|
||||||
|
return nil
|
||||||
|
} else if r, ok := ctx.Value(ctxReqLoggerKeyType{}).(*zap.Logger); ok {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetReqLogOrDefault returns log from context, if it exists.
|
||||||
|
// If the log is missing from the context, the default logger is returned.
|
||||||
|
func GetReqLogOrDefault(ctx context.Context, defaultLog *zap.Logger) *zap.Logger {
|
||||||
|
log := GetReqLog(ctx)
|
||||||
|
if log == nil {
|
||||||
|
log = defaultLog
|
||||||
|
}
|
||||||
|
return log
|
||||||
|
}
|
||||||
|
|
It's better to use issue link if it exists (#148)