Skip to content

Commit 4cc4ad7

Browse files
authored
Merge pull request #56 from ThreeDotsLabs/added-decorators
Added decorators
2 parents 36e751c + b47996a commit 4cc4ad7

37 files changed

Lines changed: 3725 additions & 2844 deletions

docker/app-prod/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.17
1+
FROM golang:1.18
22

33
ARG SERVICE
44

docker/app/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
FROM golang:1.17
1+
FROM golang:1.18
22

3-
RUN go get github.com/cespare/reflex
3+
RUN go install github.com/cespare/reflex@v0.3.1
44
COPY reflex.conf /
55

66
COPY start.sh /

docker/web/start.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
set -e
1+
set -ex
22

3-
npm install
3+
yarn install
44
yarn serve
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package decorator
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/sirupsen/logrus"
9+
)
10+
11+
func ApplyCommandDecorators[H any](handler CommandHandler[H], logger *logrus.Entry, metricsClient MetricsClient) CommandHandler[H] {
12+
return commandLoggingDecorator[H]{
13+
base: commandMetricsDecorator[H]{
14+
base: handler,
15+
client: metricsClient,
16+
},
17+
logger: logger,
18+
}
19+
}
20+
21+
type CommandHandler[C any] interface {
22+
Handle(ctx context.Context, cmd C) error
23+
}
24+
25+
func generateActionName(handler any) string {
26+
return strings.Split(fmt.Sprintf("%T", handler), ".")[1]
27+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package decorator
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/sirupsen/logrus"
8+
)
9+
10+
type commandLoggingDecorator[C any] struct {
11+
base CommandHandler[C]
12+
logger *logrus.Entry
13+
}
14+
15+
func (d commandLoggingDecorator[C]) Handle(ctx context.Context, cmd C) (err error) {
16+
handlerType := generateActionName(cmd)
17+
18+
logger := d.logger.WithFields(logrus.Fields{
19+
"command": handlerType,
20+
"command_body": fmt.Sprintf("%#v", cmd),
21+
})
22+
23+
logger.Debug("Executing command")
24+
defer func() {
25+
if err == nil {
26+
logger.Info("Command executed successfully")
27+
} else {
28+
logger.WithError(err).Error("Failed to execute command")
29+
}
30+
}()
31+
32+
return d.base.Handle(ctx, cmd)
33+
}
34+
35+
type queryLoggingDecorator[C any, R any] struct {
36+
base QueryHandler[C, R]
37+
logger *logrus.Entry
38+
}
39+
40+
func (d queryLoggingDecorator[C, R]) Handle(ctx context.Context, cmd C) (result R, err error) {
41+
logger := d.logger.WithFields(logrus.Fields{
42+
"query": generateActionName(cmd),
43+
"query_body": fmt.Sprintf("%#v", cmd),
44+
})
45+
46+
logger.Debug("Executing query")
47+
defer func() {
48+
if err == nil {
49+
logger.Info("Query executed successfully")
50+
} else {
51+
logger.WithError(err).Error("Failed to execute query")
52+
}
53+
}()
54+
55+
return d.base.Handle(ctx, cmd)
56+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package decorator
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
"time"
8+
)
9+
10+
type MetricsClient interface {
11+
Inc(key string, value int)
12+
}
13+
14+
type commandMetricsDecorator[C any] struct {
15+
base CommandHandler[C]
16+
client MetricsClient
17+
}
18+
19+
func (d commandMetricsDecorator[C]) Handle(ctx context.Context, cmd C) (err error) {
20+
start := time.Now()
21+
22+
actionName := strings.ToLower(generateActionName(cmd))
23+
24+
defer func() {
25+
end := time.Since(start)
26+
27+
d.client.Inc(fmt.Sprintf("commands.%s.duration", actionName), int(end.Seconds()))
28+
29+
if err == nil {
30+
d.client.Inc(fmt.Sprintf("commands.%s.success", actionName), 1)
31+
} else {
32+
d.client.Inc(fmt.Sprintf("commands.%s.failure", actionName), 1)
33+
}
34+
}()
35+
36+
return d.base.Handle(ctx, cmd)
37+
}
38+
39+
type queryMetricsDecorator[C any, R any] struct {
40+
base QueryHandler[C, R]
41+
client MetricsClient
42+
}
43+
44+
func (d queryMetricsDecorator[C, R]) Handle(ctx context.Context, query C) (result R, err error) {
45+
start := time.Now()
46+
47+
actionName := strings.ToLower(generateActionName(query))
48+
49+
defer func() {
50+
end := time.Since(start)
51+
52+
d.client.Inc(fmt.Sprintf("querys.%s.duration", actionName), int(end.Seconds()))
53+
54+
if err == nil {
55+
d.client.Inc(fmt.Sprintf("querys.%s.success", actionName), 1)
56+
} else {
57+
d.client.Inc(fmt.Sprintf("querys.%s.failure", actionName), 1)
58+
}
59+
}()
60+
61+
return d.base.Handle(ctx, query)
62+
}

internal/common/decorator/query.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package decorator
2+
3+
import (
4+
"context"
5+
6+
"github.com/sirupsen/logrus"
7+
)
8+
9+
func ApplyQueryDecorators[H any, R any](handler QueryHandler[H, R], logger *logrus.Entry, metricsClient MetricsClient) QueryHandler[H, R] {
10+
return queryLoggingDecorator[H, R]{
11+
base: queryMetricsDecorator[H, R]{
12+
base: handler,
13+
client: metricsClient,
14+
},
15+
logger: logger,
16+
}
17+
}
18+
19+
type QueryHandler[Q any, R any] interface {
20+
Handle(ctx context.Context, q Q) (R, error)
21+
}

internal/common/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/ThreeDotsLabs/wild-workouts-go-ddd-example/internal/common
22

3-
go 1.17
3+
go 1.18
44

55
require (
66
cloud.google.com/go v0.75.0

internal/common/logs/logrus.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@ import (
99
)
1010

1111
func Init() {
12-
logrus.SetFormatter(&logrus.JSONFormatter{
12+
SetFormatter(logrus.StandardLogger())
13+
14+
logrus.SetLevel(logrus.DebugLevel)
15+
}
16+
17+
func SetFormatter(logger *logrus.Logger) {
18+
logger.SetFormatter(&logrus.JSONFormatter{
1319
FieldMap: logrus.FieldMap{
1420
logrus.FieldKeyTime: "time",
1521
logrus.FieldKeyLevel: "severity",
@@ -18,10 +24,8 @@ func Init() {
1824
})
1925

2026
if isLocalEnv, _ := strconv.ParseBool(os.Getenv("LOCAL_ENV")); isLocalEnv {
21-
logrus.SetFormatter(&prefixed.TextFormatter{
27+
logger.SetFormatter(&prefixed.TextFormatter{
2228
ForceFormatting: true,
2329
})
2430
}
25-
26-
logrus.SetLevel(logrus.DebugLevel)
2731
}

internal/common/metrics/dummy.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package metrics
2+
3+
type NoOp struct{}
4+
5+
func (d NoOp) Inc(_ string, _ int) {
6+
// todo - add some implementation!
7+
}

0 commit comments

Comments
 (0)