Skip to content

Commit 07392c3

Browse files
authored
feat: add request IDs to error returns and logs (#70)
Resolves #66.
1 parent b63b896 commit 07392c3

File tree

11 files changed

+72
-27
lines changed

11 files changed

+72
-27
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ require (
1010
gorm.io/gorm v1.23.3
1111
)
1212

13+
require github.com/gin-contrib/requestid v0.0.3
14+
1315
require (
1416
github.com/davecgh/go-spew v1.1.1 // indirect
1517
github.com/gin-contrib/logger v0.2.2

go.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
1414
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
1515
github.com/gin-contrib/logger v0.2.2 h1:xIoUvRdmfID02X09wfq7wuWmevBTdMK1T6TQjbv5r+4=
1616
github.com/gin-contrib/logger v0.2.2/go.mod h1:6uKBteCGZF6VtxSfO1MKWl7aEu1sPSOhwCEAFPFxnnI=
17+
github.com/gin-contrib/requestid v0.0.3 h1:E6o0ThBQEQCTKwwe6w95LnYFDR5d3ExW0CB6VNpNh/g=
18+
github.com/gin-contrib/requestid v0.0.3/go.mod h1:kMVxxUiR0WHQvXMar6ozdUn4Dx9SltMNpIKBIc4AaAg=
1719
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
1820
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
1921
github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
@@ -49,6 +51,7 @@ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
4951
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
5052
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
5153
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
54+
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
5255
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
5356
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
5457
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=

internal/controllers/account.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func GetAccountTransactions(c *gin.Context) {
4545
var account models.Account
4646
err := models.DB.First(&account, c.Param("accountId")).Error
4747
if err != nil {
48-
fetchErrorHandler(c, err)
48+
FetchErrorHandler(c, err)
4949
return
5050
}
5151

@@ -86,13 +86,13 @@ func GetAccount(c *gin.Context) {
8686
var account models.Account
8787
err := models.DB.First(&account, c.Param("accountId")).Error
8888
if err != nil {
89-
fetchErrorHandler(c, err)
89+
FetchErrorHandler(c, err)
9090
return
9191
}
9292

9393
apiResponse, err := account.WithBalance()
9494
if err != nil {
95-
fetchErrorHandler(c, fmt.Errorf("could not get values for account %v: %v", account.Name, err))
95+
FetchErrorHandler(c, fmt.Errorf("could not get values for account %v: %v", account.Name, err))
9696
return
9797
}
9898

@@ -110,7 +110,7 @@ func UpdateAccount(c *gin.Context) {
110110

111111
err := models.DB.First(&account, c.Param("accountId")).Error
112112
if err != nil {
113-
fetchErrorHandler(c, err)
113+
FetchErrorHandler(c, err)
114114
return
115115
}
116116

@@ -129,7 +129,7 @@ func DeleteAccount(c *gin.Context) {
129129
var account models.Account
130130
err := models.DB.First(&account, c.Param("accountId")).Error
131131
if err != nil {
132-
fetchErrorHandler(c, err)
132+
FetchErrorHandler(c, err)
133133
return
134134
}
135135

internal/controllers/allocation.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"strconv"
66
"strings"
77

8+
"github.com/gin-contrib/requestid"
89
"github.com/rs/zerolog/log"
910

1011
"github.com/envelope-zero/backend/internal/models"
@@ -62,7 +63,7 @@ func CreateAllocation(c *gin.Context) {
6263

6364
// Print the error to the server log if it’s a server error
6465
if status == http.StatusInternalServerError {
65-
log.Error().Msgf("%T: %v", result.Error, result.Error.Error())
66+
log.Error().Str("request-id", requestid.Get(c)).Msgf("%T: %v", result.Error, result.Error.Error())
6667
}
6768

6869
c.JSON(status, gin.H{"error": errMessage})
@@ -85,7 +86,7 @@ func GetAllocation(c *gin.Context) {
8586
var allocation models.Allocation
8687
err := models.DB.First(&allocation, c.Param("allocationId")).Error
8788
if err != nil {
88-
fetchErrorHandler(c, err)
89+
FetchErrorHandler(c, err)
8990
return
9091
}
9192

@@ -98,7 +99,7 @@ func UpdateAllocation(c *gin.Context) {
9899

99100
err := models.DB.First(&allocation, c.Param("allocationId")).Error
100101
if err != nil {
101-
fetchErrorHandler(c, err)
102+
FetchErrorHandler(c, err)
102103
return
103104
}
104105

@@ -117,7 +118,7 @@ func DeleteAllocation(c *gin.Context) {
117118
var allocation models.Allocation
118119
err := models.DB.First(&allocation, c.Param("allocationId")).Error
119120
if err != nil {
120-
fetchErrorHandler(c, err)
121+
FetchErrorHandler(c, err)
121122
return
122123
}
123124

internal/controllers/budget.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func GetBudget(c *gin.Context) {
6161
var budget models.Budget
6262
err := models.DB.First(&budget, c.Param("budgetId")).Error
6363
if err != nil {
64-
fetchErrorHandler(c, err)
64+
FetchErrorHandler(c, err)
6565
return
6666
}
6767

@@ -79,7 +79,7 @@ func UpdateBudget(c *gin.Context) {
7979
err := models.DB.First(&budget, c.Param("budgetId")).Error
8080
// Return the apporpriate error: 404 if not found, 500 on all others
8181
if err != nil {
82-
fetchErrorHandler(c, err)
82+
FetchErrorHandler(c, err)
8383
return
8484
}
8585

@@ -98,7 +98,7 @@ func DeleteBudget(c *gin.Context) {
9898
var budget models.Budget
9999
err := models.DB.First(&budget, c.Param("budgetId")).Error
100100
if err != nil {
101-
fetchErrorHandler(c, err)
101+
FetchErrorHandler(c, err)
102102
return
103103
}
104104

internal/controllers/category.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func GetCategory(c *gin.Context) {
6161
var category models.Category
6262
err := models.DB.First(&category, c.Param("categoryId")).Error
6363
if err != nil {
64-
fetchErrorHandler(c, err)
64+
FetchErrorHandler(c, err)
6565
return
6666
}
6767

@@ -76,7 +76,7 @@ func UpdateCategory(c *gin.Context) {
7676

7777
err := models.DB.First(&category, c.Param("categoryId")).Error
7878
if err != nil {
79-
fetchErrorHandler(c, err)
79+
FetchErrorHandler(c, err)
8080
return
8181
}
8282

@@ -95,7 +95,7 @@ func DeleteCategory(c *gin.Context) {
9595
var category models.Category
9696
err := models.DB.First(&category, c.Param("categoryId")).Error
9797
if err != nil {
98-
fetchErrorHandler(c, err)
98+
FetchErrorHandler(c, err)
9999
return
100100
}
101101

internal/controllers/envelope.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func GetEnvelope(c *gin.Context) {
6161
var envelope models.Envelope
6262
err := models.DB.First(&envelope, c.Param("envelopeId")).Error
6363
if err != nil {
64-
fetchErrorHandler(c, err)
64+
FetchErrorHandler(c, err)
6565
return
6666
}
6767

@@ -76,7 +76,7 @@ func UpdateEnvelope(c *gin.Context) {
7676

7777
err := models.DB.First(&envelope, c.Param("envelopeId")).Error
7878
if err != nil {
79-
fetchErrorHandler(c, err)
79+
FetchErrorHandler(c, err)
8080
return
8181
}
8282

@@ -95,7 +95,7 @@ func DeleteEnvelope(c *gin.Context) {
9595
var envelope models.Envelope
9696
err := models.DB.First(&envelope, c.Param("envelopeId")).Error
9797
if err != nil {
98-
fetchErrorHandler(c, err)
98+
FetchErrorHandler(c, err)
9999
return
100100
}
101101

internal/controllers/helper.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ package controllers
22

33
import (
44
"errors"
5+
"fmt"
56
"io"
67
"net/http"
78

9+
"github.com/gin-contrib/requestid"
810
"github.com/rs/zerolog/log"
911

1012
"github.com/gin-gonic/gin"
@@ -18,7 +20,7 @@ func bindData(c *gin.Context, data interface{}) (int, error) {
1820
return http.StatusBadRequest, errors.New("request body must not be emtpy")
1921
}
2022

21-
log.Error().Msgf("%T: %v", err, err.Error())
23+
log.Error().Str("request-id", requestid.Get(c)).Msgf("%T: %v", err, err.Error())
2224
return http.StatusBadRequest, errors.New("the body of your request contains invalid or un-parseable data. Please check and try again")
2325
}
2426
return http.StatusOK, nil
@@ -38,12 +40,16 @@ func requestURL(c *gin.Context) string {
3840
return scheme + "://" + c.Request.Host + c.Request.URL.Path
3941
}
4042

41-
// fetchErrorHandler handles errors for fetching data from the database.
42-
func fetchErrorHandler(c *gin.Context, err error) {
43+
// FetchErrorHandler handles errors for fetching data from the database.
44+
func FetchErrorHandler(c *gin.Context, err error) {
4345
if errors.Is(err, gorm.ErrRecordNotFound) {
4446
c.JSON(http.StatusNotFound, gin.H{"error": "Record not found"})
4547
} else {
46-
log.Error().Msgf("%T: %v", err, err.Error())
47-
c.JSON(http.StatusInternalServerError, gin.H{"error": "An error occured on the server during your request, please contact your server administrator."})
48+
log.Error().Str("request-id", requestid.Get(c)).Msgf("%T: %v", err, err.Error())
49+
c.JSON(http.StatusInternalServerError, gin.H{
50+
"error": fmt.Sprintf(
51+
"An error occured on the server during your request, please contact your server administrator. The request id is '%v', send this to your server administrator to help them finding the problem.", requestid.Get(c),
52+
),
53+
})
4854
}
4955
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package controllers_test
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"net/http"
7+
"net/http/httptest"
8+
"testing"
9+
10+
"github.com/envelope-zero/backend/internal/controllers"
11+
"github.com/envelope-zero/backend/internal/test"
12+
"github.com/gin-gonic/gin"
13+
"github.com/stretchr/testify/assert"
14+
)
15+
16+
func TestFetchErrorHandler(t *testing.T) {
17+
recorder := httptest.NewRecorder()
18+
c, _ := gin.CreateTestContext(recorder)
19+
controllers.FetchErrorHandler(c, errors.New("Testing error"))
20+
21+
test.AssertHTTPStatus(t, http.StatusInternalServerError, recorder)
22+
23+
var apiResponse test.APIResponse
24+
err := json.NewDecoder(recorder.Body).Decode(&apiResponse)
25+
if err != nil {
26+
assert.Fail(t, "Unable to parse response from server %q into APIListResponse, '%v'", recorder.Body, err)
27+
}
28+
29+
assert.Equal(t, "An error occured on the server during your request, please contact your server administrator. The request id is '', send this to your server administrator to help them finding the problem.", apiResponse.Error)
30+
}

internal/controllers/routing.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/envelope-zero/backend/internal/models"
1010
"github.com/gin-contrib/logger"
11+
"github.com/gin-contrib/requestid"
1112
"github.com/gin-gonic/gin"
1213
"github.com/rs/zerolog"
1314
"github.com/rs/zerolog/log"
@@ -18,18 +19,20 @@ func Router() (*gin.Engine, error) {
1819
// Set up the router and middlewares
1920
r := gin.New()
2021
r.Use(gin.Recovery())
22+
r.Use(requestid.New())
2123
r.Use(logger.SetLogger(
2224
logger.WithDefaultLevel(zerolog.InfoLevel),
2325
logger.WithClientErrorLevel(zerolog.InfoLevel),
2426
logger.WithServerErrorLevel(zerolog.ErrorLevel),
2527
logger.WithLogger(func(c *gin.Context, out io.Writer, latency time.Duration) zerolog.Logger {
2628
return log.Logger.With().
29+
Str("request-id", requestid.Get(c)).
2730
Dur("latency", latency).
2831
Str("method", c.Request.Method).
2932
Str("path", c.Request.URL.Path).
3033
Int("status", c.Writer.Status()).
3134
Int("size", c.Writer.Size()).
32-
Str("userAgent", c.Request.UserAgent()).
35+
Str("user-agent", c.Request.UserAgent()).
3336
Logger()
3437
})))
3538

0 commit comments

Comments
 (0)