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) }