Skip to content

Commit

Permalink
Merge pull request #19 from spotlibs/feat/feedback-activity-monitor
Browse files Browse the repository at this point in the history
feat: feedback activity monitor
  • Loading branch information
mdanialr authored Oct 2, 2024
2 parents 4800830 + d9a46ce commit f5730f5
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 19 deletions.
3 changes: 3 additions & 0 deletions ctx/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ type Metadata struct {
ReqKodeRegion string
PathGateway string
ApiKey string
UrlPath string // UrlPath may contain the url path information coming from http request
SignaturePath string // SignaturePath may contain the signature command from artisan command
}

// Get retrieve Metadata from given context with key from this pkg.
Expand Down Expand Up @@ -69,6 +71,7 @@ func SetFromRequestHeader(c http.Context) {
ReqKodeRegion: c.Request().Header("X-Request-Kode-Region"),
ReqJenisUker: c.Request().Header("X-Request-Jenis-Uker"),
PathGateway: c.Request().Header("X-Path-Gateway"),
UrlPath: c.Request().Path(),
}
c.WithValue(keyCtx, mt)
}
Expand Down
20 changes: 17 additions & 3 deletions log/activity.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"sync"

"github.com/spotlibs/go-lib/ctx"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
Expand All @@ -13,16 +14,21 @@ var (
actZapLog *zap.Logger // actZapLog use zap log to log message, to benefit from its buffer.
)

type actLogger struct{}
type actLogger struct {
trcId string
identifier string
}

func (l actLogger) Info(m Map) {
if !isOff.Load() {
m["trace-id"] = l.trcId
m["identifier"] = l.identifier
actZapLog.Info("", zap.Any("payload", m))
}
}

// Activity start ActLogger.
func Activity(_ context.Context) ActLogger {
func Activity(c context.Context) ActLogger {
actOnce.Do(func() {
// setup log writer
actLogWriter := &writer{wr: setupLog("activity")}
Expand All @@ -36,5 +42,13 @@ func Activity(_ context.Context) ActLogger {
})
})

return actLogger{}
// - Start embedding any necessary metadata from context

trcId := ctx.GetReqId(c)
id := ctx.Get(c).UrlPath
// add any other metadata here

// - End embedding any necessary metadata from context

return actLogger{trcId: trcId, identifier: id}
}
21 changes: 15 additions & 6 deletions log/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,31 @@ var (
)

type runLogger struct {
reqId string
trcId string
identifier string
}

func (l runLogger) Info(m Map) {
if !isOff.Load() {
// add request id
m["request-id"] = l.reqId
m["trace-id"] = l.trcId
m["identifier"] = l.identifier
runZapLog.Info("", zap.Any("payload", m))
}
}
func (l runLogger) Warning(m Map) {
if !isOff.Load() {
// add request id
m["request-id"] = l.reqId
m["trace-id"] = l.trcId
m["identifier"] = l.identifier
runZapLog.Warn("", zap.Any("payload", m))
}
}
func (l runLogger) Error(m Map) {
if !isOff.Load() {
// add request id
m["request-id"] = l.reqId
m["trace-id"] = l.trcId
m["identifier"] = l.identifier
runZapLog.Error("", zap.Any("payload", m))
}
}
Expand All @@ -62,10 +66,15 @@ func Runtime(c context.Context) RunLogger {

// - Start embedding any necessary metadata from context

reqId := ctx.GetReqId(c)
trcId := ctx.GetReqId(c)
id := ctx.Get(c).UrlPath
// replace with signature in case coming from artisan command
if id == "" {
id = ctx.Get(c).SignaturePath
}
// add any other metadata here

// - End embedding any necessary metadata from context

return runLogger{reqId: reqId}
return runLogger{trcId: trcId, identifier: id}
}
11 changes: 7 additions & 4 deletions log/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ var (
)

type wrkLogger struct {
reqId string
trcId string
identifier string
}

func (l wrkLogger) Info(m Map) {
if !isOff.Load() {
// add request id
m["request-id"] = l.reqId
m["trace-id"] = l.trcId
m["identifier"] = l.identifier
wrkZapLog.Info("", zap.Any("payload", m))
}
}
Expand All @@ -48,10 +50,11 @@ func Worker(c context.Context) WorkLogger {

// - Start embedding any necessary metadata from context

reqId := ctx.GetReqId(c)
trcId := ctx.GetReqId(c)
id := ctx.Get(c).SignaturePath
// add any other metadata here

// - End embedding any necessary metadata from context

return wrkLogger{reqId: reqId}
return wrkLogger{trcId: trcId, identifier: id}
}
55 changes: 49 additions & 6 deletions middleware/activity_monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ import (
"github.com/goravel/framework/filesystem"
"github.com/spotlibs/go-lib/ctx"
"github.com/spotlibs/go-lib/log"
"github.com/spotlibs/go-lib/stdresp"
)

const msgExceedLimit = "More than 5000 character"

// formDataFile holds information of each binary file in multipart form-data.
type formDataFile struct {
Filename string `json:"filename"`
Expand Down Expand Up @@ -41,11 +44,9 @@ func apiActivityRecorder(c http.Context, start time.Time) {
default:
req = captureRequestMap(c) // treat any unhandled content-type as map
}

// transform back response to an object before capturing
var res map[string]any
if v := c.Response().Origin().Body(); v != nil {
_ = sonic.ConfigFastest.Unmarshal(v.Bytes(), &res)
// replace request if the len more than the limit 5000
if checkLength(req) > 5000 {
req = msgExceedLimit
}

// get metadata from context
Expand All @@ -64,7 +65,7 @@ func apiActivityRecorder(c http.Context, start time.Time) {
"deviceID": mt.DeviceId,
"requestTags": mt.ReqTags,
"requestBody": req,
"responseBody": res,
"responseBody": captureResponse(c),
"responseTime": time.Since(start).Milliseconds(),
"httpCode": c.Response().Origin().Status(),
"requestAt": start.Format(time.RFC3339Nano),
Expand All @@ -74,6 +75,48 @@ func apiActivityRecorder(c http.Context, start time.Time) {
log.Activity(c).Info(activityData)
}

// captureResponse capture the response body if meet the criteria and requirement.
func captureResponse(c http.Context) any {
// transform back response to an object before capturing
var res stdresp.Std
if v := c.Response().Origin().Body(); v != nil {
_ = sonic.ConfigFastest.Unmarshal(v.Bytes(), &res)

// replace data if its len more than the limit 5000
if checkLength(res.ResponseData) > 5000 {
res.ResponseData = msgExceedLimit
}
}
return res
}

func checkLength(val any) int {
if val != nil {
return 0
}

switch v := val.(type) {
case string:
return len(v)
case int:
return v
case []int:
return len(v)
case []string:
return len(v)
case map[string]int:
return len(v)
case map[string]any:
return len(v)
case map[string]string:
return len(v)
case []any:
return len(v)
default:
return 0
}
}

// captureRequestMap capture request as map and transform it to json string.
func captureRequestMap(c http.Context) any {
return c.Request().All()
Expand Down

0 comments on commit f5730f5

Please sign in to comment.