Skip to content

Commit

Permalink
Fix failed delivery were not logged with level=error #18
Browse files Browse the repository at this point in the history
  • Loading branch information
tung2744 authored Oct 15, 2024
2 parents 4db8999 + 48f8982 commit 45c9283
Show file tree
Hide file tree
Showing 19 changed files with 297 additions and 154 deletions.
17 changes: 12 additions & 5 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"errors"
"log/slog"
"net/http"
"os"
"time"
Expand All @@ -12,10 +13,16 @@ import (
"github.com/authgear/authgear-sms-gateway/pkg/lib/config"
"github.com/authgear/authgear-sms-gateway/pkg/lib/logger"
"github.com/authgear/authgear-sms-gateway/pkg/lib/sms"
"github.com/authgear/authgear-sms-gateway/pkg/lib/sms/smsclient"
)

func main() {
logger := logger.NewLogger()
stderrHandler := logger.NewTextHandler()
contextHandler := &logger.ContextHandler{
ContextKey: smsclient.SendContextKey,
Handler: stderrHandler,
}
logger := slog.New(contextHandler)

err := godotenv.Load()
if errors.Is(err, os.ErrNotExist) {
Expand All @@ -42,11 +49,11 @@ func main() {
if err != nil {
panic(err)
}
smsClientMap := sms.NewSMSClientMap(cfg, httpClient, logger)
smsProviderMap := sms.NewSMSProviderMap(cfg, httpClient, logger)
smsService := &sms.SMSService{
Logger: logger,
RootConfig: cfg,
SMSClientMap: smsClientMap,
Logger: logger,
RootConfig: cfg,
SMSProviderMap: smsProviderMap,
}

http.Handle("/healthz", &handler.HealthzHandler{})
Expand Down
8 changes: 4 additions & 4 deletions pkg/handler/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ func (c Code) HTTPStatusCode() int {
}

type ResponseBody struct {
Code Code `json:"code"`
ErrorDescription string `json:"error_description,omitempty"`
DumpedResponse []byte `json:"dumped_response,omitempty"`
Info *smsclient.SendResultInfo `json:"info,omitempty"`
Code Code `json:"code"`
ErrorDescription string `json:"error_description,omitempty"`
DumpedResponse []byte `json:"dumped_response,omitempty"`
Info *smsclient.SendContext `json:"info,omitempty"`
}
38 changes: 21 additions & 17 deletions pkg/handler/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,22 @@ func (h *SendHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}

logger := h.Logger.With(
"app_id", body.AppID,
"to", body.To,
"template_name", body.TemplateName,
"language_tag", body.LanguageTag,
)
r = r.WithContext(smsclient.WithSendContext(
r.Context(),
func(sendCtx *smsclient.SendContext) {
sendCtx.Root = &smsclient.SendContextRoot{
AppID: body.AppID,
To: body.To,
TemplateName: body.TemplateName,
LanguageTag: body.LanguageTag,
}
},
))

logger.Info("received send request")
h.Logger.InfoContext(r.Context(), "received send request")

sendResult, err := h.SMSService.Send(
r.Context(),
body.AppID,
&smsclient.SendOptions{
To: body.To,
Expand All @@ -73,22 +79,23 @@ func (h *SendHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
)

if err != nil {
var errorUnsuccessResponse *smsclient.SendResult
var errorUnsuccessResponse *smsclient.SendResultError
if errors.As(err, &errorUnsuccessResponse) {
logger.Error("unknown response",
h.Logger.ErrorContext(r.Context(), "unsuccessful response",
"dumped_response", string(errorUnsuccessResponse.DumpedResponse),
"error", err.Error(),
)
info := smsclient.GetSendContext(r.Context())
h.write(w, &ResponseBody{
Code: CodeUnknownResponse,
DumpedResponse: errorUnsuccessResponse.DumpedResponse,
ErrorDescription: err.Error(),
Info: errorUnsuccessResponse.Info,
Info: info,
})
return
}

logger.Error("unknown error",
h.Logger.ErrorContext(r.Context(), "unknown error",
"error", err.Error(),
)
h.write(w, &ResponseBody{
Expand All @@ -98,16 +105,13 @@ func (h *SendHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}

var attrs []slog.Attr
if sendResult.Info.SendResultInfoTwilio != nil && sendResult.Info.SendResultInfoTwilio.SegmentCount != nil {
attrs = append(attrs, slog.Int("segment_count", *sendResult.Info.SendResultInfoTwilio.SegmentCount))
}
logger.LogAttrs(r.Context(), slog.LevelInfo, "finished send request", attrs...)
h.Logger.InfoContext(r.Context(), "finished send request")

info := smsclient.GetSendContext(r.Context())
h.write(w, &ResponseBody{
Code: CodeOK,
DumpedResponse: sendResult.DumpedResponse,
Info: sendResult.Info,
Info: info,
})
}

Expand Down
9 changes: 9 additions & 0 deletions pkg/lib/logger/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package logger

import (
"log/slog"
)

type LoggerContexter interface {
GetAttrs() []slog.Attr
}
38 changes: 38 additions & 0 deletions pkg/lib/logger/context_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package logger

import (
"context"
"log/slog"
)

type ContextHandler struct {
ContextKey interface{}
Handler slog.Handler
}

var _ slog.Handler = &ContextHandler{}

func (h *ContextHandler) Enabled(ctx context.Context, level slog.Level) bool {
return h.Handler.Enabled(ctx, level)
}

func (h *ContextHandler) Handle(ctx context.Context, record slog.Record) error {
loggerContexter, ok := ctx.Value(h.ContextKey).(LoggerContexter)
if ok && loggerContexter != nil {
attrs := loggerContexter.GetAttrs()
record.AddAttrs(attrs...)
}
return h.Handler.Handle(ctx, record)
}

func (h *ContextHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
return &ContextHandler{
Handler: h.Handler.WithAttrs(attrs),
}
}

func (h *ContextHandler) WithGroup(name string) slog.Handler {
return &ContextHandler{
Handler: h.Handler.WithGroup(name),
}
}
10 changes: 0 additions & 10 deletions pkg/lib/logger/logger.go

This file was deleted.

10 changes: 10 additions & 0 deletions pkg/lib/logger/text_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package logger

import (
"log/slog"
"os"
)

func NewTextHandler() *slog.TextHandler {
return slog.NewTextHandler(os.Stderr, nil)
}
8 changes: 5 additions & 3 deletions pkg/lib/sms/accessyou/sendsms.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package accessyou

import (
"context"
"errors"
"io"
"log/slog"
Expand All @@ -21,6 +22,7 @@ func fixRespData(respData []byte) []byte {
}

func SendSMS(
ctx context.Context,
client *http.Client,
baseUrl string,
accountNo string,
Expand Down Expand Up @@ -69,7 +71,7 @@ func SendSMS(
if err != nil {
return nil, nil, errors.Join(
err,
&smsclient.SendResult{
&smsclient.SendResultError{
DumpedResponse: dumpedResponse,
},
)
Expand All @@ -80,13 +82,13 @@ func SendSMS(
if err != nil {
return nil, nil, errors.Join(
err,
&smsclient.SendResult{
&smsclient.SendResultError{
DumpedResponse: dumpedResponse,
},
)
}

logger.Info("accessyou response",
logger.InfoContext(ctx, "accessyou response",
"msg_id", sendSMSResponse.MessageID,
"msg_status", sendSMSResponse.Status,
"msg_status_desc", sendSMSResponse.Description,
Expand Down
4 changes: 3 additions & 1 deletion pkg/lib/sms/accessyou/sendsms_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package accessyou

import (
"bytes"
"context"
"io"
"log/slog"
"net/http"
Expand Down Expand Up @@ -36,7 +37,8 @@ func TestSendSMS(t *testing.T) {
Body(bytes.NewReader([]byte(successResponseWithBOM)))

logger := slog.New(slog.NewTextHandler(io.Discard, nil))
dumpedResponse, parsedResponse, err := SendSMS(httpClient, baseUrl, accountNo, user, pwd, sender, to, body, logger)
ctx := context.Background()
dumpedResponse, parsedResponse, err := SendSMS(ctx, httpClient, baseUrl, accountNo, user, pwd, sender, to, body, logger)

So(err, ShouldBeNil)
So(string(dumpedResponse), ShouldEqual, "HTTP/1.1 200 OK\r\nContent-Length: 131\r\n\r\n"+successResponseWithBOM)
Expand Down
22 changes: 13 additions & 9 deletions pkg/lib/sms/accessyou/smsclient.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package accessyou

import (
"context"
"log/slog"
"net/http"
"regexp"
Expand Down Expand Up @@ -48,14 +49,11 @@ func fixPhoneNumber(phoneNumber string) string {
return plusHyphensRegexp.ReplaceAllString(phoneNumber, "")
}

func (n *AccessYouClient) Send(options *smsclient.SendOptions) (*smsclient.SendResult, error) {
info := &smsclient.SendResultInfo{
SendResultInfoAccessYou: &smsclient.SendResultInfoAccessYou{},
}

func (n *AccessYouClient) Send(ctx context.Context, options *smsclient.SendOptions) (*smsclient.SendResultSuccess, error) {
to := fixPhoneNumber(string(options.To))

dumpedResponse, sendSMSResponse, err := SendSMS(
ctx,
n.Client,
n.BaseUrl,
n.AccountNo,
Expand All @@ -70,11 +68,17 @@ func (n *AccessYouClient) Send(options *smsclient.SendOptions) (*smsclient.SendR
return nil, err
}

return &smsclient.SendResult{
// Success case.
if sendSMSResponse.Status == "100" {
return &smsclient.SendResultSuccess{
DumpedResponse: dumpedResponse,
}, nil
}

// Failed case.
return nil, &smsclient.SendResultError{
DumpedResponse: dumpedResponse,
Success: sendSMSResponse.Status == "100",
Info: info,
}, nil
}
}

var _ smsclient.RawClient = &AccessYouClient{}
8 changes: 4 additions & 4 deletions pkg/lib/sms/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@ import (
"github.com/authgear/authgear-sms-gateway/pkg/lib/sms/smsclient"
)

type SMSClientMap map[string]smsclient.RawClient
type SMSProviderMap map[string]smsclient.RawClient

func NewSMSClientMap(c *config.RootConfig, httpClient *http.Client, logger *slog.Logger) SMSClientMap {
func NewSMSProviderMap(c *config.RootConfig, httpClient *http.Client, logger *slog.Logger) SMSProviderMap {
var clientMap = make(map[string]smsclient.RawClient)

for _, provider := range c.Providers {
client := NewClientFromConfigProvider(provider, httpClient, logger)
clientMap[provider.Name] = client
}

return SMSClientMap(clientMap)
return SMSProviderMap(clientMap)
}

func (s SMSClientMap) GetClientByName(name string) smsclient.RawClient {
func (s SMSProviderMap) GetProviderByName(name string) smsclient.RawClient {
client := s[name]
if client == nil {
panic(fmt.Errorf("Unknown client %v", name))
Expand Down
2 changes: 1 addition & 1 deletion pkg/lib/sms/selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/authgear/authgear-sms-gateway/pkg/lib/config"
)

func GetClientNameByMatch(c *config.RootConfig, ctx *MatchContext) string {
func GetProviderNameByMatch(c *config.RootConfig, ctx *MatchContext) string {
var defaultClient string
for _, providerSelector := range c.ProviderSelector.Switch {
matcher := ParseMatcher(providerSelector)
Expand Down
2 changes: 1 addition & 1 deletion pkg/lib/sms/selector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ provider_selector:
func TestSelector(t *testing.T) {
test := func(convey string, configYAML string, ctx *MatchContext, expectedName string) {
c, _ := config.ParseRootConfigFromYAML([]byte(configYAML))
res := GetClientNameByMatch(c, ctx)
res := GetProviderNameByMatch(c, ctx)
Convey(convey, t, func() {
So(res, ShouldEqual, expectedName)
})
Expand Down
9 changes: 5 additions & 4 deletions pkg/lib/sms/sendcloud/send.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sendcloud

import (
"context"
"errors"
"fmt"
"io"
Expand All @@ -12,7 +13,7 @@ import (
"github.com/authgear/authgear-sms-gateway/pkg/lib/sms/smsclient"
)

func Send(client *http.Client, baseUrl string, sendRequest *SendRequest, smsKey string, logger *slog.Logger) ([]byte, *SendResponse, error) {
func Send(ctx context.Context, client *http.Client, baseUrl string, sendRequest *SendRequest, smsKey string, logger *slog.Logger) ([]byte, *SendResponse, error) {
values := sendRequest.ToValues()
values.Set("signature", sendRequest.Sign(smsKey))

Expand All @@ -36,7 +37,7 @@ func Send(client *http.Client, baseUrl string, sendRequest *SendRequest, smsKey
if err != nil {
return nil, nil, errors.Join(
err,
&smsclient.SendResult{
&smsclient.SendResultError{
DumpedResponse: dumpedResponse,
},
)
Expand All @@ -46,13 +47,13 @@ func Send(client *http.Client, baseUrl string, sendRequest *SendRequest, smsKey
if err != nil {
return nil, nil, errors.Join(
err,
&smsclient.SendResult{
&smsclient.SendResultError{
DumpedResponse: dumpedResponse,
},
)
}

logger.Info("sendcloud response",
logger.InfoContext(ctx, "sendcloud response",
"result", sendResponse.Result,
"statusCode", sendResponse.StatusCode,
"message", sendResponse.Message,
Expand Down
Loading

0 comments on commit 45c9283

Please sign in to comment.