diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2686d02c2..8c68f86cf 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,7 +1,7 @@
name: CI
on: [push, pull_request]
env:
- go-version: "1.23.x"
+ go-version: "1.24.x"
jobs:
test:
name: Test
diff --git a/Dockerfile b/Dockerfile
index f85f8cb90..edb4c9586 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM golang:1.23
+FROM golang:1.24
WORKDIR /usr/src/app
diff --git a/channel_log.go b/channel_log.go
index 65b38034a..644b5e784 100644
--- a/channel_log.go
+++ b/channel_log.go
@@ -21,39 +21,39 @@ const (
)
func ErrorResponseStatusCode() *clogs.LogError {
- return clogs.NewLogError("response_status_code", "", "Unexpected response status code.")
+ return &clogs.LogError{Code: "response_status_code", Message: "Unexpected response status code."}
}
func ErrorResponseUnparseable(format string) *clogs.LogError {
- return clogs.NewLogError("response_unparseable", "", "Unable to parse response as %s.", format)
+ return &clogs.LogError{Code: "response_unparseable", Message: fmt.Sprintf("Unable to parse response as %s.", format)}
}
func ErrorResponseUnexpected(expected string) *clogs.LogError {
- return clogs.NewLogError("response_unexpected", "", "Expected response to be '%s'.", expected)
+ return &clogs.LogError{Code: "response_unexpected", Message: fmt.Sprintf("Expected response to be '%s'.", expected)}
}
func ErrorResponseValueMissing(key string) *clogs.LogError {
- return clogs.NewLogError("response_value_missing", "", "Unable to find '%s' response.", key)
+ return &clogs.LogError{Code: "response_value_missing", Message: fmt.Sprintf("Unable to find '%s' response.", key)}
}
func ErrorMediaUnsupported(contentType string) *clogs.LogError {
- return clogs.NewLogError("media_unsupported", "", "Unsupported attachment media type: %s.", contentType)
+ return &clogs.LogError{Code: "media_unsupported", Message: fmt.Sprintf("Unsupported attachment media type: %s.", contentType)}
}
// ErrorMediaUnresolveable is used when media is unresolveable due to the channel's specific requirements
func ErrorMediaUnresolveable(contentType string) *clogs.LogError {
- return clogs.NewLogError("media_unresolveable", "", "Unable to find version of %s attachment compatible with channel.", contentType)
+ return &clogs.LogError{Code: "media_unresolveable", Message: fmt.Sprintf("Unable to find version of %s attachment compatible with channel.", contentType)}
}
func ErrorAttachmentNotDecodable() *clogs.LogError {
- return clogs.NewLogError("attachment_not_decodable", "", "Unable to decode embedded attachment data.")
+ return &clogs.LogError{Code: "attachment_not_decodable", Message: "Unable to decode embedded attachment data."}
}
func ErrorExternal(code, message string) *clogs.LogError {
if message == "" {
message = fmt.Sprintf("Service specific error: %s.", code)
}
- return clogs.NewLogError("external", code, message)
+ return &clogs.LogError{Code: "external", ExtCode: code, Message: message}
}
// ChannelLog stores the HTTP traces and errors generated by an interaction with a channel.
@@ -95,7 +95,7 @@ func newChannelLog(t clogs.LogType, ch Channel, r *httpx.Recorder, attached bool
// Deprecated: channel handlers should add user-facing error messages via .Error() instead
func (l *ChannelLog) RawError(err error) {
- l.Error(clogs.NewLogError("", "", err.Error()))
+ l.Error(&clogs.LogError{Message: err.Error()})
}
func (l *ChannelLog) Channel() Channel {
diff --git a/channel_log_test.go b/channel_log_test.go
index ea4644c19..0c1171a1a 100644
--- a/channel_log_test.go
+++ b/channel_log_test.go
@@ -44,7 +44,7 @@ func TestChannelLog(t *testing.T) {
assert.EqualError(t, err, "unable to connect to server")
clog.HTTP(trace)
- clog.Error(clogs.NewLogError("not_right", "", "Something not right"))
+ clog.Error(&clogs.LogError{Code: "not_right", Message: "Something not right"})
clog.RawError(errors.New("this is an error"))
clog.End()
diff --git a/go.mod b/go.mod
index 61a600a9a..5a91c46c8 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module github.com/nyaruka/courier
-go 1.23
+go 1.24
require (
github.com/antchfx/xmlquery v1.4.3
diff --git a/handlers/dialog360/handler.go b/handlers/dialog360/handler.go
index 17d54608a..9622bf599 100644
--- a/handlers/dialog360/handler.go
+++ b/handlers/dialog360/handler.go
@@ -341,7 +341,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.Sen
// if we have more than 10 quick replies, truncate and add channel error
if len(qrs) > 10 {
- clog.Error(clogs.NewLogError("", "", "too many quick replies D3C supports only up to 10 quick replies"))
+ clog.Error(&clogs.LogError{Message: "too many quick replies D3C supports only up to 10 quick replies"})
qrs = qrs[:10]
}
@@ -437,7 +437,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.Sen
payload.Type = "interactive"
// if we have more than 10 quick replies, truncate and add channel error
if len(qrs) > 10 {
- clog.Error(clogs.NewLogError("", "", "too many quick replies D3C supports only up to 10 quick replies"))
+ clog.Error(&clogs.LogError{Message: "too many quick replies D3C supports only up to 10 quick replies"})
qrs = qrs[:10]
}
diff --git a/handlers/dialog360/handler_test.go b/handlers/dialog360/handler_test.go
index 5e231a78e..76853dd25 100644
--- a/handlers/dialog360/handler_test.go
+++ b/handlers/dialog360/handler_test.go
@@ -527,7 +527,7 @@ var SendTestCasesD3C = []OutgoingTestCase{
Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"},{"id":"4","title":"ROW5"},{"id":"5","title":"ROW6"},{"id":"6","title":"ROW7"},{"id":"7","title":"ROW8"},{"id":"8","title":"ROW9"},{"id":"9","title":"ROW10"}]}]}}}`,
}},
ExpectedExtIDs: []string{"157b5e14568e8"},
- ExpectedLogErrors: []*clogs.LogError{clogs.NewLogError("", "", "too many quick replies D3C supports only up to 10 quick replies")},
+ ExpectedLogErrors: []*clogs.LogError{&clogs.LogError{Message: "too many quick replies D3C supports only up to 10 quick replies"}},
},
{
Label: "Interactive List Message Send In Spanish",
diff --git a/handlers/meta/handlers.go b/handlers/meta/handlers.go
index 11a929a3b..0941d2387 100644
--- a/handlers/meta/handlers.go
+++ b/handlers/meta/handlers.go
@@ -839,7 +839,7 @@ func (h *handler) sendWhatsAppMsg(ctx context.Context, msg courier.MsgOut, res *
// if we have more than 10 quick replies, truncate and add channel error
if len(qrs) > 10 {
- clog.Error(clogs.NewLogError("", "", "too many quick replies WAC supports only up to 10 quick replies"))
+ clog.Error(&clogs.LogError{Message: "too many quick replies WAC supports only up to 10 quick replies"})
qrs = qrs[:10]
}
@@ -937,7 +937,7 @@ func (h *handler) sendWhatsAppMsg(ctx context.Context, msg courier.MsgOut, res *
// if we have more than 10 quick replies, truncate and add channel error
if len(qrs) > 10 {
- clog.Error(clogs.NewLogError("", "", "too many quick replies WAC supports only up to 10 quick replies"))
+ clog.Error(&clogs.LogError{Message: "too many quick replies WAC supports only up to 10 quick replies"})
qrs = qrs[:10]
}
diff --git a/handlers/meta/whataspp_test.go b/handlers/meta/whataspp_test.go
index 20cf8231a..7a059ab76 100644
--- a/handlers/meta/whataspp_test.go
+++ b/handlers/meta/whataspp_test.go
@@ -561,7 +561,7 @@ var whatsappOutgoingTests = []OutgoingTestCase{
Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"},{"id":"4","title":"ROW5"},{"id":"5","title":"ROW6"},{"id":"6","title":"ROW7"},{"id":"7","title":"ROW8"},{"id":"8","title":"ROW9"},{"id":"9","title":"ROW10"}]}]}}}`,
}},
ExpectedExtIDs: []string{"157b5e14568e8"},
- ExpectedLogErrors: []*clogs.LogError{clogs.NewLogError("", "", "too many quick replies WAC supports only up to 10 quick replies")},
+ ExpectedLogErrors: []*clogs.LogError{&clogs.LogError{Message: "too many quick replies WAC supports only up to 10 quick replies"}},
},
{
Label: "Interactive List Message Send In Spanish",
diff --git a/handlers/slack/handler.go b/handlers/slack/handler.go
index 9d17da3f2..3e5690def 100644
--- a/handlers/slack/handler.go
+++ b/handlers/slack/handler.go
@@ -213,7 +213,7 @@ func (h *handler) sendTextMsgPart(msg courier.MsgOut, token string, clog *courie
if err != nil {
return courier.ErrResponseContent
}
- clog.Error(clogs.NewLogError("", "", errDescription))
+ clog.Error(&clogs.LogError{Message: errDescription})
return courier.ErrFailedWithReason("", errDescription)
}
return nil
diff --git a/handlers/slack/handler_test.go b/handlers/slack/handler_test.go
index 0ed59a7a6..a10019ca4 100644
--- a/handlers/slack/handler_test.go
+++ b/handlers/slack/handler_test.go
@@ -213,7 +213,7 @@ var defaultSendTestCases = []OutgoingTestCase{
Body: `{"channel":"U0123ABCDEF","text":"Hello"}`,
}},
ExpectedError: courier.ErrFailedWithReason("", "invalid_auth"),
- ExpectedLogErrors: []*clogs.LogError{clogs.NewLogError("", "", "invalid_auth")},
+ ExpectedLogErrors: []*clogs.LogError{&clogs.LogError{Message: "invalid_auth"}},
},
{
Label: "Response Unexpected",
diff --git a/handlers/telesom/handler.go b/handlers/telesom/handler.go
index 0eda8d48c..8ec586fc9 100644
--- a/handlers/telesom/handler.go
+++ b/handlers/telesom/handler.go
@@ -108,7 +108,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.Sen
}
if !strings.Contains(string(respBody), "Success") {
- clog.Error(clogs.NewLogError("", "", "Received invalid response content: %s", string(respBody)))
+ clog.Error(&clogs.LogError{Message: fmt.Sprintf("Received invalid response content: %s", string(respBody))})
return courier.ErrResponseContent
}
}
diff --git a/handlers/telesom/handler_test.go b/handlers/telesom/handler_test.go
index 15397fa27..da21fcad3 100644
--- a/handlers/telesom/handler_test.go
+++ b/handlers/telesom/handler_test.go
@@ -172,7 +172,7 @@ var defaultSendTestCases = []OutgoingTestCase{
Form: url.Values{"msg": {"Simple Message"}, "to": {"0788383383"}, "from": {"2020"}, "key": {"D69BB824F88F20482B94ECF3822EBD84"}},
Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"},
}},
- ExpectedLogErrors: []*clogs.LogError{clogs.NewLogError("", "", "Received invalid response content: Missing")},
+ ExpectedLogErrors: []*clogs.LogError{&clogs.LogError{Message: "Received invalid response content: Missing"}},
ExpectedError: courier.ErrResponseContent,
},
}
diff --git a/sender.go b/sender.go
index 802d04c4b..fcf1f2e12 100644
--- a/sender.go
+++ b/sender.go
@@ -386,7 +386,7 @@ func (w *Sender) sendByHandler(ctx context.Context, h ChannelHandler, m MsgOut,
status.SetStatus(MsgStatusFailed)
}
- clog.Error(clogs.NewLogError(serr.clogCode, serr.clogExtCode, serr.clogMsg))
+ clog.Error(&clogs.LogError{Code: serr.clogCode, ExtCode: serr.clogExtCode, Message: serr.clogMsg})
// if handler returned ErrContactStopped need to write a stop event
if serr == ErrContactStopped {
@@ -401,7 +401,7 @@ func (w *Sender) sendByHandler(ctx context.Context, h ChannelHandler, m MsgOut,
status.SetStatus(MsgStatusErrored)
- clog.Error(clogs.NewLogError("internal_error", "", "An internal error occured."))
+ clog.Error(&clogs.LogError{Code: "internal_error", Message: "An internal error occured."})
}
return status
diff --git a/server_test.go b/server_test.go
index 8fd48fb6b..1302f2698 100644
--- a/server_test.go
+++ b/server_test.go
@@ -164,7 +164,7 @@ func TestOutgoing(t *testing.T) {
// and we should have a channel log with redacted errors and traces
assert.Len(t, mb.WrittenChannelLogs(), 1)
clog := mb.WrittenChannelLogs()[0]
- assert.Equal(t, []*clogs.LogError{clogs.NewLogError("seeds", "", "contains ********** seeds")}, clog.Errors)
+ assert.Equal(t, []*clogs.LogError{&clogs.LogError{Code: "seeds", Message: "contains ********** seeds"}}, clog.Errors)
assert.True(t, clog.Attached())
assert.Len(t, clog.HttpLogs, 1)
diff --git a/test/handler.go b/test/handler.go
index e090992de..f5d0a471a 100644
--- a/test/handler.go
+++ b/test/handler.go
@@ -60,7 +60,7 @@ func (h *mockHandler) Send(ctx context.Context, msg courier.MsgOut, res *courier
}
// log an error than contains a value that should be redacted
- clog.Error(clogs.NewLogError("seeds", "", "contains sesame seeds"))
+ clog.Error(&clogs.LogError{Code: "seeds", Message: "contains sesame seeds"})
if msg.Text() == "err:config" {
return courier.ErrChannelConfig
diff --git a/utils/clogs/clog.go b/utils/clogs/clog.go
index 60a9ff0d7..12b969126 100644
--- a/utils/clogs/clog.go
+++ b/utils/clogs/clog.go
@@ -33,11 +33,6 @@ type LogError struct {
Message string `json:"message"`
}
-// NewLogError creates a new log error
-func NewLogError(code, extCode, message string, args ...any) *LogError {
- return &LogError{Code: code, ExtCode: extCode, Message: fmt.Sprintf(message, args...)}
-}
-
// Redact applies the given redactor to this error
func (e *LogError) Redact(r stringsx.Redactor) *LogError {
return &LogError{Code: e.Code, ExtCode: e.ExtCode, Message: r(e.Message)}
diff --git a/utils/clogs/clog_test.go b/utils/clogs/clog_test.go
index 202b2f8d9..021cea75d 100644
--- a/utils/clogs/clog_test.go
+++ b/utils/clogs/clog_test.go
@@ -38,7 +38,7 @@ func TestLogs(t *testing.T) {
require.NoError(t, err)
clog2.HTTP(trace2)
- clog2.Error(clogs.NewLogError("", "", "oops"))
+ clog2.Error(&clogs.LogError{Message: "oops"})
clog2.End()
assert.NotEqual(t, clog1.UUID, clog2.UUID)
@@ -48,10 +48,10 @@ func TestLogs(t *testing.T) {
require.NoError(t, err)
l1 := clogs.NewLog("test_type1", nil, nil)
- l1.Error(clogs.NewLogError("code1", "ext", "message"))
+ l1.Error(&clogs.LogError{Code: "code1", ExtCode: "ext", Message: "message"})
l2 := clogs.NewLog("test_type2", nil, nil)
- l2.Error(clogs.NewLogError("code2", "ext", "message"))
+ l2.Error(&clogs.LogError{Code: "code2", ExtCode: "ext", Message: "message"})
// write both logs to db
err = ds.PutItem(ctx, "ChannelLogs", l1)
@@ -65,7 +65,7 @@ func TestLogs(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, l1.UUID, l3.UUID)
assert.Equal(t, clogs.LogType("test_type1"), l3.Type)
- assert.Equal(t, []*clogs.LogError{clogs.NewLogError("code1", "ext", "message")}, l3.Errors)
+ assert.Equal(t, []*clogs.LogError{{Code: "code1", ExtCode: "ext", Message: "message"}}, l3.Errors)
assert.Equal(t, l1.Elapsed, l3.Elapsed)
assert.Equal(t, l1.CreatedOn.Truncate(time.Second), l3.CreatedOn)
}