refactor: create logx package (#584)

This commit is contained in:
Bo-Yi Wu 2021-07-13 16:32:39 +08:00 committed by GitHub
parent bcb9a33d43
commit 35e1998cc5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 343 additions and 207 deletions

17
core/core.go Normal file
View File

@ -0,0 +1,17 @@
package core
const (
// PlatFormIos constant is 1 for iOS
PlatFormIos = iota + 1
// PlatFormAndroid constant is 2 for Android
PlatFormAndroid
// PlatFormHuawei constant is 3 for Huawei
PlatFormHuawei
)
const (
// SucceededPush is log block
SucceededPush = "succeeded-push"
// FailedPush is log block
FailedPush = "failed-push"
)

View File

@ -1,21 +1,5 @@
package gorush package gorush
const (
// PlatFormIos constant is 1 for iOS
PlatFormIos = iota + 1
// PlatFormAndroid constant is 2 for Android
PlatFormAndroid
// PlatFormHuawei constant is 3 for Huawei
PlatFormHuawei
)
const (
// SucceededPush is log block
SucceededPush = "succeeded-push"
// FailedPush is log block
FailedPush = "failed-push"
)
// Stat variable for redis // Stat variable for redis
const ( const (
TotalCountKey = "gorush-total-count" TotalCountKey = "gorush-total-count"

View File

@ -7,10 +7,12 @@ import (
"net" "net"
"net/http" "net/http"
"time" "time"
"github.com/appleboy/gorush/logx"
) )
// DispatchFeedback sends a feedback to the configured gateway. // DispatchFeedback sends a feedback to the configured gateway.
func DispatchFeedback(log LogPushEntry, url string, timeout int64) error { func DispatchFeedback(log logx.LogPushEntry, url string, timeout int64) error {
if url == "" { if url == "" {
return errors.New("The url can't be empty") return errors.New("The url can't be empty")
} }

View File

@ -7,13 +7,14 @@ import (
"testing" "testing"
"github.com/appleboy/gorush/config" "github.com/appleboy/gorush/config"
"github.com/appleboy/gorush/logx"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestEmptyFeedbackURL(t *testing.T) { func TestEmptyFeedbackURL(t *testing.T) {
// PushConf, _ = config.LoadConf("") // PushConf, _ = config.LoadConf("")
logEntry := LogPushEntry{ logEntry := logx.LogPushEntry{
ID: "", ID: "",
Type: "", Type: "",
Platform: "", Platform: "",
@ -29,7 +30,7 @@ func TestEmptyFeedbackURL(t *testing.T) {
func TestHTTPErrorInFeedbackCall(t *testing.T) { func TestHTTPErrorInFeedbackCall(t *testing.T) {
config, _ := config.LoadConf("") config, _ := config.LoadConf("")
config.Core.FeedbackURL = "http://test.example.com/api/" config.Core.FeedbackURL = "http://test.example.com/api/"
logEntry := LogPushEntry{ logEntry := logx.LogPushEntry{
ID: "", ID: "",
Type: "", Type: "",
Platform: "", Platform: "",
@ -60,7 +61,7 @@ func TestSuccessfulFeedbackCall(t *testing.T) {
config, _ := config.LoadConf("") config, _ := config.LoadConf("")
config.Core.FeedbackURL = httpMock.URL config.Core.FeedbackURL = httpMock.URL
logEntry := LogPushEntry{ logEntry := logx.LogPushEntry{
ID: "", ID: "",
Type: "", Type: "",
Platform: "", Platform: "",

View File

@ -7,7 +7,6 @@ import (
"github.com/appleboy/go-fcm" "github.com/appleboy/go-fcm"
"github.com/msalihkarakasli/go-hms-push/push/core" "github.com/msalihkarakasli/go-hms-push/push/core"
"github.com/sideshow/apns2" "github.com/sideshow/apns2"
"github.com/sirupsen/logrus"
) )
var ( var (
@ -21,10 +20,6 @@ var (
FCMClient *fcm.Client FCMClient *fcm.Client
// HMSClient is Huawei push client // HMSClient is Huawei push client
HMSClient *core.HMSClient HMSClient *core.HMSClient
// LogAccess is log server request log
LogAccess *logrus.Logger
// LogError is log server error log
LogError *logrus.Logger
// StatStorage implements the storage interface // StatStorage implements the storage interface
StatStorage storage.Storage StatStorage storage.Storage
// MaxConcurrentIOSPushes pool to limit the number of concurrent iOS pushes // MaxConcurrentIOSPushes pool to limit the number of concurrent iOS pushes

View File

@ -7,11 +7,17 @@ import (
"testing" "testing"
"github.com/appleboy/gorush/config" "github.com/appleboy/gorush/config"
"github.com/appleboy/gorush/logx"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
PushConf, _ = config.LoadConf("") PushConf, _ = config.LoadConf("")
if err := InitLog(); err != nil { if err := logx.InitLog(
PushConf.Log.AccessLevel,
PushConf.Log.AccessLog,
PushConf.Log.ErrorLevel,
PushConf.Log.ErrorLog,
); err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -9,6 +9,8 @@ import (
"sync" "sync"
"github.com/appleboy/go-fcm" "github.com/appleboy/go-fcm"
"github.com/appleboy/gorush/core"
"github.com/appleboy/gorush/logx"
"github.com/msalihkarakasli/go-hms-push/push/model" "github.com/msalihkarakasli/go-hms-push/push/model"
) )
@ -53,7 +55,7 @@ type RequestPush struct {
// PushNotification is single notification request // PushNotification is single notification request
type PushNotification struct { type PushNotification struct {
wg *sync.WaitGroup wg *sync.WaitGroup
log *[]LogPushEntry log *[]logx.LogPushEntry
// Common // Common
ID string `json:"notif_id,omitempty"` ID string `json:"notif_id,omitempty"`
@ -123,7 +125,7 @@ func (p *PushNotification) AddWaitCount() {
} }
// AddLog record fail log of notification // AddLog record fail log of notification
func (p *PushNotification) AddLog(log LogPushEntry) { func (p *PushNotification) AddLog(log logx.LogPushEntry) {
if p.log != nil { if p.log != nil {
*p.log = append(*p.log, log) *p.log = append(*p.log, log)
} }
@ -132,11 +134,11 @@ func (p *PushNotification) AddLog(log LogPushEntry) {
// IsTopic check if message format is topic for FCM // IsTopic check if message format is topic for FCM
// ref: https://firebase.google.com/docs/cloud-messaging/send-message#topic-http-post-request // ref: https://firebase.google.com/docs/cloud-messaging/send-message#topic-http-post-request
func (p *PushNotification) IsTopic() bool { func (p *PushNotification) IsTopic() bool {
if p.Platform == PlatFormAndroid { if p.Platform == core.PlatFormAndroid {
return p.To != "" && strings.HasPrefix(p.To, "/topics/") || p.Condition != "" return p.To != "" && strings.HasPrefix(p.To, "/topics/") || p.Condition != ""
} }
if p.Platform == PlatFormHuawei { if p.Platform == core.PlatFormHuawei {
return p.Topic != "" || p.Condition != "" return p.Topic != "" || p.Condition != ""
} }
@ -150,33 +152,33 @@ func CheckMessage(req PushNotification) error {
// ignore send topic mesaage from FCM // ignore send topic mesaage from FCM
if !req.IsTopic() && len(req.Tokens) == 0 && req.To == "" { if !req.IsTopic() && len(req.Tokens) == 0 && req.To == "" {
msg = "the message must specify at least one registration ID" msg = "the message must specify at least one registration ID"
LogAccess.Debug(msg) logx.LogAccess.Debug(msg)
return errors.New(msg) return errors.New(msg)
} }
if len(req.Tokens) == PlatFormIos && req.Tokens[0] == "" { if len(req.Tokens) == core.PlatFormIos && req.Tokens[0] == "" {
msg = "the token must not be empty" msg = "the token must not be empty"
LogAccess.Debug(msg) logx.LogAccess.Debug(msg)
return errors.New(msg) return errors.New(msg)
} }
if req.Platform == PlatFormAndroid && len(req.Tokens) > 1000 { if req.Platform == core.PlatFormAndroid && len(req.Tokens) > 1000 {
msg = "the message may specify at most 1000 registration IDs" msg = "the message may specify at most 1000 registration IDs"
LogAccess.Debug(msg) logx.LogAccess.Debug(msg)
return errors.New(msg) return errors.New(msg)
} }
if req.Platform == PlatFormHuawei && len(req.Tokens) > 500 { if req.Platform == core.PlatFormHuawei && len(req.Tokens) > 500 {
msg = "the message may specify at most 500 registration IDs for Huawei" msg = "the message may specify at most 500 registration IDs for Huawei"
LogAccess.Debug(msg) logx.LogAccess.Debug(msg)
return errors.New(msg) return errors.New(msg)
} }
// ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref // ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref
if req.Platform == PlatFormAndroid && req.TimeToLive != nil && *req.TimeToLive > uint(2419200) { if req.Platform == core.PlatFormAndroid && req.TimeToLive != nil && *req.TimeToLive > uint(2419200) {
msg = "the message's TimeToLive field must be an integer " + msg = "the message's TimeToLive field must be an integer " +
"between 0 and 2419200 (4 weeks)" "between 0 and 2419200 (4 weeks)"
LogAccess.Debug(msg) logx.LogAccess.Debug(msg)
return errors.New(msg) return errors.New(msg)
} }
@ -191,7 +193,7 @@ func SetProxy(proxy string) error {
} }
http.DefaultTransport = &http.Transport{Proxy: http.ProxyURL(proxyURL)} http.DefaultTransport = &http.Transport{Proxy: http.ProxyURL(proxyURL)}
LogAccess.Debug("Set http proxy as " + proxy) logx.LogAccess.Debug("Set http proxy as " + proxy)
return nil return nil
} }

View File

@ -11,6 +11,9 @@ import (
"sync" "sync"
"time" "time"
"github.com/appleboy/gorush/core"
"github.com/appleboy/gorush/logx"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/sideshow/apns2" "github.com/sideshow/apns2"
"github.com/sideshow/apns2/certificate" "github.com/sideshow/apns2/certificate"
@ -68,7 +71,7 @@ func InitAPNSClient() error {
} }
if err != nil { if err != nil {
LogError.Error("Cert Error:", err.Error()) logx.LogError.Error("Cert Error:", err.Error())
return err return err
} }
@ -76,7 +79,7 @@ func InitAPNSClient() error {
ext = "." + PushConf.Ios.KeyType ext = "." + PushConf.Ios.KeyType
key, err := base64.StdEncoding.DecodeString(PushConf.Ios.KeyBase64) key, err := base64.StdEncoding.DecodeString(PushConf.Ios.KeyBase64)
if err != nil { if err != nil {
LogError.Error("base64 decode error:", err.Error()) logx.LogError.Error("base64 decode error:", err.Error())
return err return err
} }
@ -92,7 +95,7 @@ func InitAPNSClient() error {
} }
if err != nil { if err != nil {
LogError.Error("Cert Error:", err.Error()) logx.LogError.Error("Cert Error:", err.Error())
return err return err
} }
@ -101,7 +104,7 @@ func InitAPNSClient() error {
if ext == ".p8" { if ext == ".p8" {
if PushConf.Ios.KeyID == "" || PushConf.Ios.TeamID == "" { if PushConf.Ios.KeyID == "" || PushConf.Ios.TeamID == "" {
msg := "You should provide ios.KeyID and ios.TeamID for P8 token" msg := "You should provide ios.KeyID and ios.TeamID for P8 token"
LogError.Error(msg) logx.LogError.Error(msg)
return errors.New(msg) return errors.New(msg)
} }
token := &token.Token{ token := &token.Token{
@ -122,7 +125,7 @@ func InitAPNSClient() error {
} }
if err != nil { if err != nil {
LogError.Error("Transport Error:", err.Error()) logx.LogError.Error("Transport Error:", err.Error())
return err return err
} }
@ -378,7 +381,7 @@ func getApnsClient(req PushNotification) (client *apns2.Client) {
// PushToIOS provide send notification to APNs server. // PushToIOS provide send notification to APNs server.
func PushToIOS(req PushNotification) { func PushToIOS(req PushNotification) {
LogAccess.Debug("Start push notification for iOS") logx.LogAccess.Debug("Start push notification for iOS")
var ( var (
retryCount = 0 retryCount = 0
@ -412,17 +415,17 @@ Retry:
err = errors.New(res.Reason) err = errors.New(res.Reason)
} }
// apns server error // apns server error
LogPush(FailedPush, token, req, err) logPush(core.FailedPush, token, req, err)
if PushConf.Core.Sync { if PushConf.Core.Sync {
req.AddLog(getLogPushEntry(FailedPush, token, req, err)) req.AddLog(createLogPushEntry(core.FailedPush, token, req, err))
} else if PushConf.Core.FeedbackURL != "" { } else if PushConf.Core.FeedbackURL != "" {
go func(logger *logrus.Logger, log LogPushEntry, url string, timeout int64) { go func(logger *logrus.Logger, log logx.LogPushEntry, url string, timeout int64) {
err := DispatchFeedback(log, url, timeout) err := DispatchFeedback(log, url, timeout)
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
} }
}(LogError, getLogPushEntry(FailedPush, token, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout) }(logx.LogError, createLogPushEntry(core.FailedPush, token, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
} }
StatStorage.AddIosError(1) StatStorage.AddIosError(1)
@ -434,7 +437,7 @@ Retry:
} }
if res != nil && res.Sent() { if res != nil && res.Sent() {
LogPush(SucceededPush, token, req, nil) logPush(core.SucceededPush, token, req, nil)
StatStorage.AddIosSuccess(1) StatStorage.AddIosSuccess(1)
} }
// free push slot // free push slot

View File

@ -11,6 +11,7 @@ import (
"time" "time"
"github.com/appleboy/gorush/config" "github.com/appleboy/gorush/config"
"github.com/appleboy/gorush/core"
"github.com/buger/jsonparser" "github.com/buger/jsonparser"
"github.com/sideshow/apns2" "github.com/sideshow/apns2"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -583,13 +584,13 @@ func TestDisabledIosNotifications(t *testing.T) {
// ios // ios
{ {
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"}, Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
Platform: PlatFormIos, Platform: core.PlatFormIos,
Message: "Welcome", Message: "Welcome",
}, },
// android // android
{ {
Tokens: []string{androidToken, androidToken + "_"}, Tokens: []string{androidToken, androidToken + "_"},
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Message: "Welcome", Message: "Welcome",
}, },
}, },

View File

@ -5,6 +5,8 @@ import (
"fmt" "fmt"
"github.com/appleboy/go-fcm" "github.com/appleboy/go-fcm"
"github.com/appleboy/gorush/core"
"github.com/appleboy/gorush/logx"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -102,7 +104,7 @@ func GetAndroidNotification(req PushNotification) *fcm.Message {
// PushToAndroid provide send notification to Android server. // PushToAndroid provide send notification to Android server.
func PushToAndroid(req PushNotification) { func PushToAndroid(req PushNotification) {
LogAccess.Debug("Start push notification for Android") logx.LogAccess.Debug("Start push notification for Android")
var ( var (
client *fcm.Client client *fcm.Client
@ -117,7 +119,7 @@ func PushToAndroid(req PushNotification) {
// check message // check message
err := CheckMessage(req) err := CheckMessage(req)
if err != nil { if err != nil {
LogError.Error("request error: " + err.Error()) logx.LogError.Error("request error: " + err.Error())
return return
} }
@ -132,38 +134,38 @@ Retry:
if err != nil { if err != nil {
// FCM server error // FCM server error
LogError.Error("FCM server error: " + err.Error()) logx.LogError.Error("FCM server error: " + err.Error())
return return
} }
res, err := client.Send(notification) res, err := client.Send(notification)
if err != nil { if err != nil {
// Send Message error // Send Message error
LogError.Error("FCM server send message error: " + err.Error()) logx.LogError.Error("FCM server send message error: " + err.Error())
if req.IsTopic() { if req.IsTopic() {
if PushConf.Core.Sync { if PushConf.Core.Sync {
req.AddLog(getLogPushEntry(FailedPush, req.To, req, err)) req.AddLog(createLogPushEntry(core.FailedPush, req.To, req, err))
} else if PushConf.Core.FeedbackURL != "" { } else if PushConf.Core.FeedbackURL != "" {
go func(logger *logrus.Logger, log LogPushEntry, url string, timeout int64) { go func(logger *logrus.Logger, log logx.LogPushEntry, url string, timeout int64) {
err := DispatchFeedback(log, url, timeout) err := DispatchFeedback(log, url, timeout)
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
} }
}(LogError, getLogPushEntry(FailedPush, req.To, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout) }(logx.LogError, createLogPushEntry(core.FailedPush, req.To, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
} }
StatStorage.AddAndroidError(1) StatStorage.AddAndroidError(1)
} else { } else {
for _, token := range req.Tokens { for _, token := range req.Tokens {
if PushConf.Core.Sync { if PushConf.Core.Sync {
req.AddLog(getLogPushEntry(FailedPush, token, req, err)) req.AddLog(createLogPushEntry(core.FailedPush, token, req, err))
} else if PushConf.Core.FeedbackURL != "" { } else if PushConf.Core.FeedbackURL != "" {
go func(logger *logrus.Logger, log LogPushEntry, url string, timeout int64) { go func(logger *logrus.Logger, log logx.LogPushEntry, url string, timeout int64) {
err := DispatchFeedback(log, url, timeout) err := DispatchFeedback(log, url, timeout)
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
} }
}(LogError, getLogPushEntry(FailedPush, token, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout) }(logx.LogError, createLogPushEntry(core.FailedPush, token, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
} }
} }
StatStorage.AddAndroidError(int64(len(req.Tokens))) StatStorage.AddAndroidError(int64(len(req.Tokens)))
@ -172,7 +174,7 @@ Retry:
} }
if !req.IsTopic() { if !req.IsTopic() {
LogAccess.Debug(fmt.Sprintf("Android Success count: %d, Failure count: %d", res.Success, res.Failure)) logx.LogAccess.Debug(fmt.Sprintf("Android Success count: %d, Failure count: %d", res.Success, res.Failure))
} }
StatStorage.AddAndroidSuccess(int64(res.Success)) StatStorage.AddAndroidSuccess(int64(res.Success))
@ -195,21 +197,21 @@ Retry:
newTokens = append(newTokens, to) newTokens = append(newTokens, to)
} }
LogPush(FailedPush, to, req, result.Error) logPush(core.FailedPush, to, req, result.Error)
if PushConf.Core.Sync { if PushConf.Core.Sync {
req.AddLog(getLogPushEntry(FailedPush, to, req, result.Error)) req.AddLog(createLogPushEntry(core.FailedPush, to, req, result.Error))
} else if PushConf.Core.FeedbackURL != "" { } else if PushConf.Core.FeedbackURL != "" {
go func(logger *logrus.Logger, log LogPushEntry, url string, timeout int64) { go func(logger *logrus.Logger, log logx.LogPushEntry, url string, timeout int64) {
err := DispatchFeedback(log, url, timeout) err := DispatchFeedback(log, url, timeout)
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
} }
}(LogError, getLogPushEntry(FailedPush, to, req, result.Error), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout) }(logx.LogError, createLogPushEntry(core.FailedPush, to, req, result.Error), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
} }
continue continue
} }
LogPush(SucceededPush, to, req, nil) logPush(core.SucceededPush, to, req, nil)
} }
// result from Send messages to topics // result from Send messages to topics
@ -220,15 +222,15 @@ Retry:
} else { } else {
to = req.Condition to = req.Condition
} }
LogAccess.Debug("Send Topic Message: ", to) logx.LogAccess.Debug("Send Topic Message: ", to)
// Success // Success
if res.MessageID != 0 { if res.MessageID != 0 {
LogPush(SucceededPush, to, req, nil) logPush(core.SucceededPush, to, req, nil)
} else { } else {
// failure // failure
LogPush(FailedPush, to, req, res.Error) logPush(core.FailedPush, to, req, res.Error)
if PushConf.Core.Sync { if PushConf.Core.Sync {
req.AddLog(getLogPushEntry(FailedPush, to, req, res.Error)) req.AddLog(createLogPushEntry(core.FailedPush, to, req, res.Error))
} }
} }
} }
@ -237,9 +239,9 @@ Retry:
if len(res.FailedRegistrationIDs) > 0 { if len(res.FailedRegistrationIDs) > 0 {
newTokens = append(newTokens, res.FailedRegistrationIDs...) newTokens = append(newTokens, res.FailedRegistrationIDs...)
LogPush(FailedPush, notification.To, req, errors.New("device group: partial success or all fails")) logPush(core.FailedPush, notification.To, req, errors.New("device group: partial success or all fails"))
if PushConf.Core.Sync { if PushConf.Core.Sync {
req.AddLog(getLogPushEntry(FailedPush, notification.To, req, errors.New("device group: partial success or all fails"))) req.AddLog(createLogPushEntry(core.FailedPush, notification.To, req, errors.New("device group: partial success or all fails")))
} }
} }
@ -251,3 +253,29 @@ Retry:
goto Retry goto Retry
} }
} }
func createLogPushEntry(status, token string, req PushNotification, err error) logx.LogPushEntry {
return logx.GetLogPushEntry(&logx.InputLog{
ID: req.ID,
Status: status,
Token: token,
Message: req.Message,
Platform: req.Platform,
Error: err,
HideToken: PushConf.Log.HideToken,
Format: PushConf.Log.Format,
})
}
func logPush(status, token string, req PushNotification, err error) {
logx.LogPush(&logx.InputLog{
ID: req.ID,
Status: status,
Token: token,
Message: req.Message,
Platform: req.Platform,
Error: err,
HideToken: PushConf.Log.HideToken,
Format: PushConf.Log.Format,
})
}

View File

@ -4,8 +4,11 @@ import (
"os" "os"
"testing" "testing"
"github.com/appleboy/go-fcm"
"github.com/appleboy/gorush/config" "github.com/appleboy/gorush/config"
"github.com/appleboy/gorush/core"
"github.com/appleboy/gorush/logx"
"github.com/appleboy/go-fcm"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -37,7 +40,7 @@ func TestPushToAndroidWrongToken(t *testing.T) {
req := PushNotification{ req := PushNotification{
Tokens: []string{"aaaaaa", "bbbbb"}, Tokens: []string{"aaaaaa", "bbbbb"},
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Message: "Welcome", Message: "Welcome",
} }
@ -57,7 +60,7 @@ func TestPushToAndroidRightTokenForJSONLog(t *testing.T) {
req := PushNotification{ req := PushNotification{
Tokens: []string{androidToken}, Tokens: []string{androidToken},
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Message: "Welcome", Message: "Welcome",
} }
@ -74,7 +77,7 @@ func TestPushToAndroidRightTokenForStringLog(t *testing.T) {
req := PushNotification{ req := PushNotification{
Tokens: []string{androidToken}, Tokens: []string{androidToken},
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Message: "Welcome", Message: "Welcome",
} }
@ -92,12 +95,12 @@ func TestOverwriteAndroidAPIKey(t *testing.T) {
req := PushNotification{ req := PushNotification{
Tokens: []string{androidToken, "bbbbb"}, Tokens: []string{androidToken, "bbbbb"},
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Message: "Welcome", Message: "Welcome",
// overwrite android api key // overwrite android api key
APIKey: "1234", APIKey: "1234",
log: &[]LogPushEntry{}, log: &[]logx.LogPushEntry{},
} }
// FCM server error: 401 error: 401 Unauthorized (Wrong API Key) // FCM server error: 401 error: 401 Unauthorized (Wrong API Key)
@ -131,7 +134,7 @@ func TestFCMMessage(t *testing.T) {
// ignore check token length if send topic message // ignore check token length if send topic message
req = PushNotification{ req = PushNotification{
Message: "Test", Message: "Test",
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
To: "/topics/foo-bar", To: "/topics/foo-bar",
} }
@ -141,7 +144,7 @@ func TestFCMMessage(t *testing.T) {
// "condition": "'dogs' in topics || 'cats' in topics", // "condition": "'dogs' in topics || 'cats' in topics",
req = PushNotification{ req = PushNotification{
Message: "Test", Message: "Test",
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Condition: "'dogs' in topics || 'cats' in topics", Condition: "'dogs' in topics || 'cats' in topics",
} }
@ -151,7 +154,7 @@ func TestFCMMessage(t *testing.T) {
// the message may specify at most 1000 registration IDs // the message may specify at most 1000 registration IDs
req = PushNotification{ req = PushNotification{
Message: "Test", Message: "Test",
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Tokens: make([]string, 1001), Tokens: make([]string, 1001),
} }
@ -163,7 +166,7 @@ func TestFCMMessage(t *testing.T) {
timeToLive := uint(2419201) timeToLive := uint(2419201)
req = PushNotification{ req = PushNotification{
Message: "Test", Message: "Test",
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Tokens: []string{"XXXXXXXXX"}, Tokens: []string{"XXXXXXXXX"},
TimeToLive: &timeToLive, TimeToLive: &timeToLive,
} }
@ -175,7 +178,7 @@ func TestFCMMessage(t *testing.T) {
timeToLive = uint(86400) timeToLive = uint(86400)
req = PushNotification{ req = PushNotification{
Message: "Test", Message: "Test",
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Tokens: []string{"XXXXXXXXX"}, Tokens: []string{"XXXXXXXXX"},
TimeToLive: &timeToLive, TimeToLive: &timeToLive,
} }
@ -193,7 +196,7 @@ func TestCheckAndroidMessage(t *testing.T) {
timeToLive := uint(2419201) timeToLive := uint(2419201)
req := PushNotification{ req := PushNotification{
Tokens: []string{"aaaaaa", "bbbbb"}, Tokens: []string{"aaaaaa", "bbbbb"},
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Message: "Welcome", Message: "Welcome",
TimeToLive: &timeToLive, TimeToLive: &timeToLive,
} }

View File

@ -6,6 +6,8 @@ import (
"errors" "errors"
"sync" "sync"
"github.com/appleboy/gorush/logx"
"github.com/msalihkarakasli/go-hms-push/push/config" "github.com/msalihkarakasli/go-hms-push/push/config"
"github.com/msalihkarakasli/go-hms-push/push/core" "github.com/msalihkarakasli/go-hms-push/push/core"
"github.com/msalihkarakasli/go-hms-push/push/model" "github.com/msalihkarakasli/go-hms-push/push/model"
@ -153,17 +155,17 @@ func GetHuaweiNotification(req PushNotification) (*model.MessageRequest, error)
b, err := json.Marshal(msgRequest) b, err := json.Marshal(msgRequest)
if err != nil { if err != nil {
LogError.Error("Failed to marshal the default message! Error is " + err.Error()) logx.LogError.Error("Failed to marshal the default message! Error is " + err.Error())
return nil, err return nil, err
} }
LogAccess.Debugf("Default message is %s", string(b)) logx.LogAccess.Debugf("Default message is %s", string(b))
return msgRequest, nil return msgRequest, nil
} }
// PushToHuawei provide send notification to Android server. // PushToHuawei provide send notification to Android server.
func PushToHuawei(req PushNotification) bool { func PushToHuawei(req PushNotification) bool {
LogAccess.Debug("Start push notification for Huawei") logx.LogAccess.Debug("Start push notification for Huawei")
var ( var (
client *core.HMSClient client *core.HMSClient
@ -178,7 +180,7 @@ func PushToHuawei(req PushNotification) bool {
// check message // check message
err := CheckMessage(req) err := CheckMessage(req)
if err != nil { if err != nil {
LogError.Error("request error: " + err.Error()) logx.LogError.Error("request error: " + err.Error())
return false return false
} }
@ -191,25 +193,25 @@ Retry:
if err != nil { if err != nil {
// HMS server error // HMS server error
LogError.Error("HMS server error: " + err.Error()) logx.LogError.Error("HMS server error: " + err.Error())
return false return false
} }
res, err := client.SendMessage(context.Background(), notification) res, err := client.SendMessage(context.Background(), notification)
if err != nil { if err != nil {
// Send Message error // Send Message error
LogError.Error("HMS server send message error: " + err.Error()) logx.LogError.Error("HMS server send message error: " + err.Error())
return false return false
} }
// Huawei Push Send API does not support exact results for each token // Huawei Push Send API does not support exact results for each token
if res.Code == "80000000" { if res.Code == "80000000" {
StatStorage.AddHuaweiSuccess(int64(1)) StatStorage.AddHuaweiSuccess(int64(1))
LogAccess.Debug("Huwaei Send Notification is completed successfully!") logx.LogAccess.Debug("Huwaei Send Notification is completed successfully!")
} else { } else {
isError = true isError = true
StatStorage.AddHuaweiError(int64(1)) StatStorage.AddHuaweiError(int64(1))
LogAccess.Debug("Huawei Send Notification is failed! Code: " + res.Code) logx.LogAccess.Debug("Huawei Send Notification is failed! Code: " + res.Code)
} }
if isError && retryCount < maxRetry { if isError && retryCount < maxRetry {

View File

@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/appleboy/gorush/config" "github.com/appleboy/gorush/config"
"github.com/appleboy/gorush/core"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -42,13 +43,13 @@ func TestSenMultipleNotifications(t *testing.T) {
// ios // ios
{ {
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"}, Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
Platform: PlatFormIos, Platform: core.PlatFormIos,
Message: "Welcome", Message: "Welcome",
}, },
// android // android
{ {
Tokens: []string{androidToken, "bbbbb"}, Tokens: []string{androidToken, "bbbbb"},
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Message: "Welcome", Message: "Welcome",
}, },
}, },
@ -78,13 +79,13 @@ func TestDisabledAndroidNotifications(t *testing.T) {
// ios // ios
{ {
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"}, Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
Platform: PlatFormIos, Platform: core.PlatFormIos,
Message: "Welcome", Message: "Welcome",
}, },
// android // android
{ {
Tokens: []string{androidToken, "bbbbb"}, Tokens: []string{androidToken, "bbbbb"},
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Message: "Welcome", Message: "Welcome",
}, },
}, },
@ -117,13 +118,13 @@ func TestSyncModeForNotifications(t *testing.T) {
// ios // ios
{ {
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"}, Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
Platform: PlatFormIos, Platform: core.PlatFormIos,
Message: "Welcome", Message: "Welcome",
}, },
// android // android
{ {
Tokens: []string{androidToken, "bbbbb"}, Tokens: []string{androidToken, "bbbbb"},
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Message: "Welcome", Message: "Welcome",
}, },
}, },
@ -152,21 +153,21 @@ func TestSyncModeForTopicNotification(t *testing.T) {
// error:InvalidParameters // error:InvalidParameters
// Check that the provided parameters have the right name and type. // Check that the provided parameters have the right name and type.
To: "/topics/foo-bar@@@##", To: "/topics/foo-bar@@@##",
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Message: "This is a Firebase Cloud Messaging Topic Message!", Message: "This is a Firebase Cloud Messaging Topic Message!",
}, },
// android // android
{ {
// success // success
To: "/topics/foo-bar", To: "/topics/foo-bar",
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Message: "This is a Firebase Cloud Messaging Topic Message!", Message: "This is a Firebase Cloud Messaging Topic Message!",
}, },
// android // android
{ {
// success // success
Condition: "'dogs' in topics || 'cats' in topics", Condition: "'dogs' in topics || 'cats' in topics",
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Message: "This is a Firebase Cloud Messaging Topic Message!", Message: "This is a Firebase Cloud Messaging Topic Message!",
}, },
}, },
@ -193,7 +194,7 @@ func TestSyncModeForDeviceGroupNotification(t *testing.T) {
// android // android
{ {
To: "aUniqueKey", To: "aUniqueKey",
Platform: PlatFormAndroid, Platform: core.PlatFormAndroid,
Message: "This is a Firebase Cloud Messaging Device Group Message!", Message: "This is a Firebase Cloud Messaging Device Group Message!",
}, },
}, },

View File

@ -8,9 +8,11 @@ import (
"os" "os"
api "github.com/appleboy/gin-status-api" api "github.com/appleboy/gin-status-api"
"github.com/appleboy/gorush/logx"
"github.com/gin-contrib/logger" "github.com/gin-contrib/logger"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding" "github.com/gin-gonic/gin/binding"
"github.com/mattn/go-isatty"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/rs/zerolog" "github.com/rs/zerolog"
@ -18,10 +20,13 @@ import (
"golang.org/x/crypto/acme/autocert" "golang.org/x/crypto/acme/autocert"
) )
var isTerm bool
func init() { func init() {
// Support metrics // Support metrics
m := NewMetrics() m := NewMetrics()
prometheus.MustRegister(m) prometheus.MustRegister(m)
isTerm = isatty.IsTerminal(os.Stdout.Fd())
} }
func abortWithError(c *gin.Context, code int, message string) { func abortWithError(c *gin.Context, code int, message string) {
@ -54,21 +59,21 @@ func pushHandler(c *gin.Context) {
if err := c.ShouldBindWith(&form, binding.JSON); err != nil { if err := c.ShouldBindWith(&form, binding.JSON); err != nil {
msg = "Missing notifications field." msg = "Missing notifications field."
LogAccess.Debug(err) logx.LogAccess.Debug(err)
abortWithError(c, http.StatusBadRequest, msg) abortWithError(c, http.StatusBadRequest, msg)
return return
} }
if len(form.Notifications) == 0 { if len(form.Notifications) == 0 {
msg = "Notifications field is empty." msg = "Notifications field is empty."
LogAccess.Debug(msg) logx.LogAccess.Debug(msg)
abortWithError(c, http.StatusBadRequest, msg) abortWithError(c, http.StatusBadRequest, msg)
return return
} }
if int64(len(form.Notifications)) > PushConf.Core.MaxNotification { if int64(len(form.Notifications)) > PushConf.Core.MaxNotification {
msg = fmt.Sprintf("Number of notifications(%d) over limit(%d)", len(form.Notifications), PushConf.Core.MaxNotification) msg = fmt.Sprintf("Number of notifications(%d) over limit(%d)", len(form.Notifications), PushConf.Core.MaxNotification)
LogAccess.Debug(msg) logx.LogAccess.Debug(msg)
abortWithError(c, http.StatusBadRequest, msg) abortWithError(c, http.StatusBadRequest, msg)
return return
} }

View File

@ -10,6 +10,8 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/appleboy/gorush/logx"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
@ -18,7 +20,7 @@ func RunHTTPServer(ctx context.Context, s ...*http.Server) (err error) {
var server *http.Server var server *http.Server
if !PushConf.Core.Enabled { if !PushConf.Core.Enabled {
LogAccess.Info("httpd server is disabled.") logx.LogAccess.Info("httpd server is disabled.")
return nil return nil
} }
@ -31,7 +33,7 @@ func RunHTTPServer(ctx context.Context, s ...*http.Server) (err error) {
server = s[0] server = s[0]
} }
LogAccess.Info("HTTPD server is running on " + PushConf.Core.Port + " port.") logx.LogAccess.Info("HTTPD server is running on " + PushConf.Core.Port + " port.")
if PushConf.Core.AutoTLS.Enabled { if PushConf.Core.AutoTLS.Enabled {
return startServer(ctx, autoTLSServer()) return startServer(ctx, autoTLSServer())
} else if PushConf.Core.SSL { } else if PushConf.Core.SSL {
@ -47,22 +49,22 @@ func RunHTTPServer(ctx context.Context, s ...*http.Server) (err error) {
if PushConf.Core.CertPath != "" && PushConf.Core.KeyPath != "" { if PushConf.Core.CertPath != "" && PushConf.Core.KeyPath != "" {
config.Certificates[0], err = tls.LoadX509KeyPair(PushConf.Core.CertPath, PushConf.Core.KeyPath) config.Certificates[0], err = tls.LoadX509KeyPair(PushConf.Core.CertPath, PushConf.Core.KeyPath)
if err != nil { if err != nil {
LogError.Error("Failed to load https cert file: ", err) logx.LogError.Error("Failed to load https cert file: ", err)
return err return err
} }
} else if PushConf.Core.CertBase64 != "" && PushConf.Core.KeyBase64 != "" { } else if PushConf.Core.CertBase64 != "" && PushConf.Core.KeyBase64 != "" {
cert, err := base64.StdEncoding.DecodeString(PushConf.Core.CertBase64) cert, err := base64.StdEncoding.DecodeString(PushConf.Core.CertBase64)
if err != nil { if err != nil {
LogError.Error("base64 decode error:", err.Error()) logx.LogError.Error("base64 decode error:", err.Error())
return err return err
} }
key, err := base64.StdEncoding.DecodeString(PushConf.Core.KeyBase64) key, err := base64.StdEncoding.DecodeString(PushConf.Core.KeyBase64)
if err != nil { if err != nil {
LogError.Error("base64 decode error:", err.Error()) logx.LogError.Error("base64 decode error:", err.Error())
return err return err
} }
if config.Certificates[0], err = tls.X509KeyPair(cert, key); err != nil { if config.Certificates[0], err = tls.X509KeyPair(cert, key); err != nil {
LogError.Error("tls key pair error:", err.Error()) logx.LogError.Error("tls key pair error:", err.Error())
return err return err
} }
} else { } else {

View File

@ -12,6 +12,7 @@ import (
"time" "time"
"github.com/appleboy/gorush/config" "github.com/appleboy/gorush/config"
"github.com/appleboy/gorush/core"
"github.com/appleboy/gofight/v2" "github.com/appleboy/gofight/v2"
"github.com/buger/jsonparser" "github.com/buger/jsonparser"
@ -279,7 +280,7 @@ func TestMutableContent(t *testing.T) {
"notifications": []gofight.D{ "notifications": []gofight.D{
{ {
"tokens": []string{"aaaaa", "bbbbb"}, "tokens": []string{"aaaaa", "bbbbb"},
"platform": PlatFormAndroid, "platform": core.PlatFormAndroid,
"message": "Welcome", "message": "Welcome",
"mutable_content": 1, "mutable_content": 1,
"topic": "test", "topic": "test",
@ -310,12 +311,12 @@ func TestOutOfRangeMaxNotifications(t *testing.T) {
"notifications": []gofight.D{ "notifications": []gofight.D{
{ {
"tokens": []string{"aaaaa", "bbbbb"}, "tokens": []string{"aaaaa", "bbbbb"},
"platform": PlatFormAndroid, "platform": core.PlatFormAndroid,
"message": "Welcome", "message": "Welcome",
}, },
{ {
"tokens": []string{"aaaaa", "bbbbb"}, "tokens": []string{"aaaaa", "bbbbb"},
"platform": PlatFormAndroid, "platform": core.PlatFormAndroid,
"message": "Welcome", "message": "Welcome",
}, },
}, },
@ -341,7 +342,7 @@ func TestSuccessPushHandler(t *testing.T) {
"notifications": []gofight.D{ "notifications": []gofight.D{
{ {
"tokens": []string{androidToken, "bbbbb"}, "tokens": []string{androidToken, "bbbbb"},
"platform": PlatFormAndroid, "platform": core.PlatFormAndroid,
"message": "Welcome", "message": "Welcome",
}, },
}, },

View File

@ -4,6 +4,7 @@ import (
"errors" "errors"
"net/http" "net/http"
"github.com/appleboy/gorush/logx"
"github.com/appleboy/gorush/storage/badger" "github.com/appleboy/gorush/storage/badger"
"github.com/appleboy/gorush/storage/boltdb" "github.com/appleboy/gorush/storage/boltdb"
"github.com/appleboy/gorush/storage/buntdb" "github.com/appleboy/gorush/storage/buntdb"
@ -49,7 +50,7 @@ type HuaweiStatus struct {
// InitAppStatus for initialize app status // InitAppStatus for initialize app status
func InitAppStatus() error { func InitAppStatus() error {
LogAccess.Info("Init App Status Engine as ", PushConf.Stat.Engine) logx.LogAccess.Info("Init App Status Engine as ", PushConf.Stat.Engine)
switch PushConf.Stat.Engine { switch PushConf.Stat.Engine {
case "memory": case "memory":
StatStorage = memory.New() StatStorage = memory.New()
@ -64,12 +65,12 @@ func InitAppStatus() error {
case "badger": case "badger":
StatStorage = badger.New(PushConf) StatStorage = badger.New(PushConf)
default: default:
LogError.Error("storage error: can't find storage driver") logx.LogError.Error("storage error: can't find storage driver")
return errors.New("can't find storage driver") return errors.New("can't find storage driver")
} }
if err := StatStorage.Init(); err != nil { if err := StatStorage.Init(); err != nil {
LogError.Error("storage error: " + err.Error()) logx.LogError.Error("storage error: " + err.Error())
return err return err
} }

View File

@ -4,11 +4,14 @@ import (
"context" "context"
"errors" "errors"
"sync" "sync"
"github.com/appleboy/gorush/core"
"github.com/appleboy/gorush/logx"
) )
// InitWorkers for initialize all workers. // InitWorkers for initialize all workers.
func InitWorkers(ctx context.Context, wg *sync.WaitGroup, workerNum, queueNum int64) { func InitWorkers(ctx context.Context, wg *sync.WaitGroup, workerNum, queueNum int64) {
LogAccess.Info("worker number is ", workerNum, ", queue number is ", queueNum) logx.LogAccess.Info("worker number is ", workerNum, ", queue number is ", queueNum)
QueueNotification = make(chan PushNotification, queueNum) QueueNotification = make(chan PushNotification, queueNum)
for i := int64(0); i < workerNum; i++ { for i := int64(0); i < workerNum; i++ {
go startWorker(ctx, wg, i) go startWorker(ctx, wg, i)
@ -22,11 +25,11 @@ func SendNotification(ctx context.Context, req PushNotification) {
} }
switch req.Platform { switch req.Platform {
case PlatFormIos: case core.PlatFormIos:
PushToIOS(req) PushToIOS(req)
case PlatFormAndroid: case core.PlatFormAndroid:
PushToAndroid(req) PushToAndroid(req)
case PlatFormHuawei: case core.PlatFormHuawei:
PushToHuawei(req) PushToHuawei(req)
} }
} }
@ -36,35 +39,44 @@ func startWorker(ctx context.Context, wg *sync.WaitGroup, num int64) {
for notification := range QueueNotification { for notification := range QueueNotification {
SendNotification(ctx, notification) SendNotification(ctx, notification)
} }
LogAccess.Info("closed the worker num ", num) logx.LogAccess.Info("closed the worker num ", num)
} }
// markFailedNotification adds failure logs for all tokens in push notification // markFailedNotification adds failure logs for all tokens in push notification
func markFailedNotification(notification *PushNotification, reason string) { func markFailedNotification(notification *PushNotification, reason string) {
LogError.Error(reason) logx.LogError.Error(reason)
for _, token := range notification.Tokens { for _, token := range notification.Tokens {
notification.AddLog(getLogPushEntry(FailedPush, token, *notification, errors.New(reason))) notification.AddLog(logx.GetLogPushEntry(&logx.InputLog{
ID: notification.ID,
Status: core.FailedPush,
Token: token,
Message: notification.Message,
Platform: notification.Platform,
Error: errors.New(reason),
HideToken: PushConf.Log.HideToken,
Format: PushConf.Log.Format,
}))
} }
notification.WaitDone() notification.WaitDone()
} }
// queueNotification add notification to queue list. // queueNotification add notification to queue list.
func queueNotification(ctx context.Context, req RequestPush) (int, []LogPushEntry) { func queueNotification(ctx context.Context, req RequestPush) (int, []logx.LogPushEntry) {
var count int var count int
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
newNotification := []*PushNotification{} newNotification := []*PushNotification{}
for i := range req.Notifications { for i := range req.Notifications {
notification := &req.Notifications[i] notification := &req.Notifications[i]
switch notification.Platform { switch notification.Platform {
case PlatFormIos: case core.PlatFormIos:
if !PushConf.Ios.Enabled { if !PushConf.Ios.Enabled {
continue continue
} }
case PlatFormAndroid: case core.PlatFormAndroid:
if !PushConf.Android.Enabled { if !PushConf.Android.Enabled {
continue continue
} }
case PlatFormHuawei: case core.PlatFormHuawei:
if !PushConf.Huawei.Enabled { if !PushConf.Huawei.Enabled {
continue continue
} }
@ -72,7 +84,7 @@ func queueNotification(ctx context.Context, req RequestPush) (int, []LogPushEntr
newNotification = append(newNotification, notification) newNotification = append(newNotification, notification)
} }
log := make([]LogPushEntry, 0, count) log := make([]logx.LogPushEntry, 0, count)
for _, notification := range newNotification { for _, notification := range newNotification {
if PushConf.Core.Sync { if PushConf.Core.Sync {
notification.wg = &wg notification.wg = &wg

View File

@ -1,4 +1,4 @@
package gorush package logx
import ( import (
"encoding/json" "encoding/json"
@ -7,6 +7,8 @@ import (
"os" "os"
"strings" "strings"
"github.com/appleboy/gorush/core"
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -38,8 +40,15 @@ func init() {
isTerm = isatty.IsTerminal(os.Stdout.Fd()) isTerm = isatty.IsTerminal(os.Stdout.Fd())
} }
var (
// LogAccess is log server request log
LogAccess *logrus.Logger
// LogError is log server error log
LogError *logrus.Logger
)
// InitLog use for initial log module // InitLog use for initial log module
func InitLog() error { func InitLog(accessLevel, accessLog, errorLevel, errorLog string) error {
var err error var err error
// init logger // init logger
@ -62,19 +71,19 @@ func InitLog() error {
} }
// set logger // set logger
if err = SetLogLevel(LogAccess, PushConf.Log.AccessLevel); err != nil { if err = SetLogLevel(LogAccess, accessLevel); err != nil {
return errors.New("Set access log level error: " + err.Error()) return errors.New("Set access log level error: " + err.Error())
} }
if err = SetLogLevel(LogError, PushConf.Log.ErrorLevel); err != nil { if err = SetLogLevel(LogError, errorLevel); err != nil {
return errors.New("Set error log level error: " + err.Error()) return errors.New("Set error log level error: " + err.Error())
} }
if err = SetLogOut(LogAccess, PushConf.Log.AccessLog); err != nil { if err = SetLogOut(LogAccess, accessLog); err != nil {
return errors.New("Set access log path error: " + err.Error()) return errors.New("Set access log path error: " + err.Error())
} }
if err = SetLogOut(LogError, PushConf.Log.ErrorLog); err != nil { if err = SetLogOut(LogError, errorLog); err != nil {
return errors.New("Set error log path error: " + err.Error()) return errors.New("Set error log path error: " + err.Error())
} }
@ -115,11 +124,11 @@ func SetLogLevel(log *logrus.Logger, levelString string) error {
func colorForPlatForm(platform int) string { func colorForPlatForm(platform int) string {
switch platform { switch platform {
case PlatFormIos: case core.PlatFormIos:
return blue return blue
case PlatFormAndroid: case core.PlatFormAndroid:
return yellow return yellow
case PlatFormHuawei: case core.PlatFormHuawei:
return green return green
default: default:
return reset return reset
@ -128,11 +137,11 @@ func colorForPlatForm(platform int) string {
func typeForPlatForm(platform int) string { func typeForPlatForm(platform int) string {
switch platform { switch platform {
case PlatFormIos: case core.PlatFormIos:
return "ios" return "ios"
case PlatFormAndroid: case core.PlatFormAndroid:
return "android" return "android"
case PlatFormHuawei: case core.PlatFormHuawei:
return "huawei" return "huawei"
default: default:
return "" return ""
@ -157,48 +166,62 @@ func hideToken(token string, markLen int) string {
return result return result
} }
func getLogPushEntry(status, token string, req PushNotification, errPush error) LogPushEntry { // GetLogPushEntry get push data into log structure
func GetLogPushEntry(input *InputLog) LogPushEntry {
var errMsg string var errMsg string
var token string
plat := typeForPlatForm(req.Platform) plat := typeForPlatForm(input.Platform)
if errPush != nil { if input.Error != nil {
errMsg = errPush.Error() errMsg = input.Error.Error()
} }
if PushConf.Log.HideToken { if input.HideToken {
token = hideToken(token, 10) token = hideToken(input.Token, 10)
} }
return LogPushEntry{ return LogPushEntry{
ID: req.ID, ID: input.ID,
Type: status, Type: input.Status,
Platform: plat, Platform: plat,
Token: token, Token: token,
Message: req.Message, Message: input.Message,
Error: errMsg, Error: errMsg,
} }
} }
// InputLog log request
type InputLog struct {
ID string
Status string
Token string
Message string
Platform int
Error error
HideToken bool
Format string
}
// LogPush record user push request and server response. // LogPush record user push request and server response.
func LogPush(status, token string, req PushNotification, errPush error) { func LogPush(input *InputLog) {
var platColor, resetColor, output string var platColor, resetColor, output string
if isTerm { if isTerm {
platColor = colorForPlatForm(req.Platform) platColor = colorForPlatForm(input.Platform)
resetColor = reset resetColor = reset
} }
log := getLogPushEntry(status, token, req, errPush) log := GetLogPushEntry(input)
if PushConf.Log.Format == "json" { if input.Format == "json" {
logJSON, _ := json.Marshal(log) logJSON, _ := json.Marshal(log)
output = string(logJSON) output = string(logJSON)
} else { } else {
var typeColor string var typeColor string
switch status { switch input.Status {
case SucceededPush: case core.SucceededPush:
if isTerm { if isTerm {
typeColor = green typeColor = green
} }
@ -209,7 +232,7 @@ func LogPush(status, token string, req PushNotification, errPush error) {
log.Token, log.Token,
log.Message, log.Message,
) )
case FailedPush: case core.FailedPush:
if isTerm { if isTerm {
typeColor = red typeColor = red
} }
@ -224,10 +247,10 @@ func LogPush(status, token string, req PushNotification, errPush error) {
} }
} }
switch status { switch input.Status {
case SucceededPush: case core.SucceededPush:
LogAccess.Info(output) LogAccess.Info(output)
case FailedPush: case core.FailedPush:
LogError.Error(output) LogError.Error(output)
} }
} }

0
logx/log/access.log Normal file
View File

View File

@ -1,9 +1,11 @@
package gorush package logx
import ( import (
"testing" "testing"
"github.com/appleboy/gorush/config" "github.com/appleboy/gorush/config"
"github.com/appleboy/gorush/core"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -36,57 +38,87 @@ func TestSetLogOut(t *testing.T) {
} }
func TestInitDefaultLog(t *testing.T) { func TestInitDefaultLog(t *testing.T) {
PushConf, _ = config.LoadConf("") PushConf, _ := config.LoadConf("")
// no errors on default config // no errors on default config
assert.Nil(t, InitLog()) assert.Nil(t, InitLog(
PushConf.Log.AccessLevel,
PushConf.Log.AccessLog,
PushConf.Log.ErrorLevel,
PushConf.Log.ErrorLog,
))
PushConf.Log.AccessLevel = "invalid" PushConf.Log.AccessLevel = "invalid"
assert.NotNil(t, InitLog()) assert.NotNil(t, InitLog(
PushConf.Log.AccessLevel,
PushConf.Log.AccessLog,
PushConf.Log.ErrorLevel,
PushConf.Log.ErrorLog,
))
} }
func TestAccessLevel(t *testing.T) { func TestAccessLevel(t *testing.T) {
PushConf, _ = config.LoadConf("") PushConf, _ := config.LoadConf("")
PushConf.Log.AccessLevel = "invalid" PushConf.Log.AccessLevel = "invalid"
assert.NotNil(t, InitLog()) assert.NotNil(t, InitLog(
PushConf.Log.AccessLevel,
PushConf.Log.AccessLog,
PushConf.Log.ErrorLevel,
PushConf.Log.ErrorLog,
))
} }
func TestErrorLevel(t *testing.T) { func TestErrorLevel(t *testing.T) {
PushConf, _ = config.LoadConf("") PushConf, _ := config.LoadConf("")
PushConf.Log.ErrorLevel = "invalid" PushConf.Log.ErrorLevel = "invalid"
assert.NotNil(t, InitLog()) assert.NotNil(t, InitLog(
PushConf.Log.AccessLevel,
PushConf.Log.AccessLog,
PushConf.Log.ErrorLevel,
PushConf.Log.ErrorLog,
))
} }
func TestAccessLogPath(t *testing.T) { func TestAccessLogPath(t *testing.T) {
PushConf, _ = config.LoadConf("") PushConf, _ := config.LoadConf("")
PushConf.Log.AccessLog = "logs/access.log" PushConf.Log.AccessLog = "logs/access.log"
assert.NotNil(t, InitLog()) assert.NotNil(t, InitLog(
PushConf.Log.AccessLevel,
PushConf.Log.AccessLog,
PushConf.Log.ErrorLevel,
PushConf.Log.ErrorLog,
))
} }
func TestErrorLogPath(t *testing.T) { func TestErrorLogPath(t *testing.T) {
PushConf, _ = config.LoadConf("") PushConf, _ := config.LoadConf("")
PushConf.Log.ErrorLog = "logs/error.log" PushConf.Log.ErrorLog = "logs/error.log"
assert.NotNil(t, InitLog()) assert.NotNil(t, InitLog(
PushConf.Log.AccessLevel,
PushConf.Log.AccessLog,
PushConf.Log.ErrorLevel,
PushConf.Log.ErrorLog,
))
} }
func TestPlatFormType(t *testing.T) { func TestPlatFormType(t *testing.T) {
assert.Equal(t, "ios", typeForPlatForm(PlatFormIos)) assert.Equal(t, "ios", typeForPlatForm(core.PlatFormIos))
assert.Equal(t, "android", typeForPlatForm(PlatFormAndroid)) assert.Equal(t, "android", typeForPlatForm(core.PlatFormAndroid))
assert.Equal(t, "", typeForPlatForm(10000)) assert.Equal(t, "", typeForPlatForm(10000))
} }
func TestPlatFormColor(t *testing.T) { func TestPlatFormColor(t *testing.T) {
assert.Equal(t, blue, colorForPlatForm(PlatFormIos)) assert.Equal(t, blue, colorForPlatForm(core.PlatFormIos))
assert.Equal(t, yellow, colorForPlatForm(PlatFormAndroid)) assert.Equal(t, yellow, colorForPlatForm(core.PlatFormAndroid))
assert.Equal(t, reset, colorForPlatForm(1000000)) assert.Equal(t, reset, colorForPlatForm(1000000))
} }

47
main.go
View File

@ -16,7 +16,9 @@ import (
"time" "time"
"github.com/appleboy/gorush/config" "github.com/appleboy/gorush/config"
"github.com/appleboy/gorush/core"
"github.com/appleboy/gorush/gorush" "github.com/appleboy/gorush/gorush"
"github.com/appleboy/gorush/logx"
"github.com/appleboy/gorush/rpc" "github.com/appleboy/gorush/rpc"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
@ -158,7 +160,12 @@ func main() {
gorush.PushConf.Core.Address = opts.Core.Address gorush.PushConf.Core.Address = opts.Core.Address
} }
if err = gorush.InitLog(); err != nil { if err = logx.InitLog(
gorush.PushConf.Log.AccessLevel,
gorush.PushConf.Log.AccessLog,
gorush.PushConf.Log.ErrorLevel,
gorush.PushConf.Log.ErrorLog,
); err != nil {
log.Fatalf("Can't load log module, error: %v", err) log.Fatalf("Can't load log module, error: %v", err)
} }
@ -170,13 +177,13 @@ func main() {
err = gorush.SetProxy(gorush.PushConf.Core.HTTPProxy) err = gorush.SetProxy(gorush.PushConf.Core.HTTPProxy)
if err != nil { if err != nil {
gorush.LogError.Fatalf("Set Proxy error: %v", err) logx.LogError.Fatalf("Set Proxy error: %v", err)
} }
} }
if ping { if ping {
if err := pinger(); err != nil { if err := pinger(); err != nil {
gorush.LogError.Warnf("ping server error: %v", err) logx.LogError.Warnf("ping server error: %v", err)
} }
return return
} }
@ -185,7 +192,7 @@ func main() {
if opts.Android.Enabled { if opts.Android.Enabled {
gorush.PushConf.Android.Enabled = opts.Android.Enabled gorush.PushConf.Android.Enabled = opts.Android.Enabled
req := gorush.PushNotification{ req := gorush.PushNotification{
Platform: gorush.PlatFormAndroid, Platform: core.PlatFormAndroid,
Message: message, Message: message,
Title: title, Title: title,
} }
@ -202,7 +209,7 @@ func main() {
err := gorush.CheckMessage(req) err := gorush.CheckMessage(req)
if err != nil { if err != nil {
gorush.LogError.Fatal(err) logx.LogError.Fatal(err)
} }
if err := gorush.InitAppStatus(); err != nil { if err := gorush.InitAppStatus(); err != nil {
@ -218,7 +225,7 @@ func main() {
if opts.Huawei.Enabled { if opts.Huawei.Enabled {
gorush.PushConf.Huawei.Enabled = opts.Huawei.Enabled gorush.PushConf.Huawei.Enabled = opts.Huawei.Enabled
req := gorush.PushNotification{ req := gorush.PushNotification{
Platform: gorush.PlatFormHuawei, Platform: core.PlatFormHuawei,
Message: message, Message: message,
Title: title, Title: title,
} }
@ -235,7 +242,7 @@ func main() {
err := gorush.CheckMessage(req) err := gorush.CheckMessage(req)
if err != nil { if err != nil {
gorush.LogError.Fatal(err) logx.LogError.Fatal(err)
} }
if err := gorush.InitAppStatus(); err != nil { if err := gorush.InitAppStatus(); err != nil {
@ -255,7 +262,7 @@ func main() {
gorush.PushConf.Ios.Enabled = opts.Ios.Enabled gorush.PushConf.Ios.Enabled = opts.Ios.Enabled
req := gorush.PushNotification{ req := gorush.PushNotification{
Platform: gorush.PlatFormIos, Platform: core.PlatFormIos,
Message: message, Message: message,
Title: title, Title: title,
} }
@ -272,7 +279,7 @@ func main() {
err := gorush.CheckMessage(req) err := gorush.CheckMessage(req)
if err != nil { if err != nil {
gorush.LogError.Fatal(err) logx.LogError.Fatal(err)
} }
if err := gorush.InitAppStatus(); err != nil { if err := gorush.InitAppStatus(); err != nil {
@ -288,7 +295,7 @@ func main() {
} }
if err = gorush.CheckPushConf(); err != nil { if err = gorush.CheckPushConf(); err != nil {
gorush.LogError.Fatal(err) logx.LogError.Fatal(err)
} }
if opts.Core.PID.Path != "" { if opts.Core.PID.Path != "" {
@ -298,26 +305,26 @@ func main() {
} }
if err = createPIDFile(); err != nil { if err = createPIDFile(); err != nil {
gorush.LogError.Fatal(err) logx.LogError.Fatal(err)
} }
if err = gorush.InitAppStatus(); err != nil { if err = gorush.InitAppStatus(); err != nil {
gorush.LogError.Fatal(err) logx.LogError.Fatal(err)
} }
finished := make(chan struct{}) finished := make(chan struct{})
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(int(gorush.PushConf.Core.WorkerNum)) wg.Add(int(gorush.PushConf.Core.WorkerNum))
ctx := withContextFunc(context.Background(), func() { ctx := withContextFunc(context.Background(), func() {
gorush.LogAccess.Info("close the notification queue channel, current queue len: ", len(gorush.QueueNotification)) logx.LogAccess.Info("close the notification queue channel, current queue len: ", len(gorush.QueueNotification))
close(gorush.QueueNotification) close(gorush.QueueNotification)
wg.Wait() wg.Wait()
gorush.LogAccess.Info("the notification queue has been clear") logx.LogAccess.Info("the notification queue has been clear")
close(finished) close(finished)
// close the connection with storage // close the connection with storage
gorush.LogAccess.Info("close the storage connection: ", gorush.PushConf.Stat.Engine) logx.LogAccess.Info("close the storage connection: ", gorush.PushConf.Stat.Engine)
if err := gorush.StatStorage.Close(); err != nil { if err := gorush.StatStorage.Close(); err != nil {
gorush.LogError.Fatal("can't close the storage connection: ", err.Error()) logx.LogError.Fatal("can't close the storage connection: ", err.Error())
} }
}) })
@ -325,19 +332,19 @@ func main() {
if gorush.PushConf.Ios.Enabled { if gorush.PushConf.Ios.Enabled {
if err = gorush.InitAPNSClient(); err != nil { if err = gorush.InitAPNSClient(); err != nil {
gorush.LogError.Fatal(err) logx.LogError.Fatal(err)
} }
} }
if gorush.PushConf.Android.Enabled { if gorush.PushConf.Android.Enabled {
if _, err = gorush.InitFCMClient(gorush.PushConf.Android.APIKey); err != nil { if _, err = gorush.InitFCMClient(gorush.PushConf.Android.APIKey); err != nil {
gorush.LogError.Fatal(err) logx.LogError.Fatal(err)
} }
} }
if gorush.PushConf.Huawei.Enabled { if gorush.PushConf.Huawei.Enabled {
if _, err = gorush.InitHMSClient(gorush.PushConf.Huawei.AppSecret, gorush.PushConf.Huawei.AppID); err != nil { if _, err = gorush.InitHMSClient(gorush.PushConf.Huawei.AppSecret, gorush.PushConf.Huawei.AppID); err != nil {
gorush.LogError.Fatal(err) logx.LogError.Fatal(err)
} }
} }
@ -362,7 +369,7 @@ func main() {
}) })
if err = g.Wait(); err != nil { if err = g.Wait(); err != nil {
gorush.LogError.Fatal(err) logx.LogError.Fatal(err)
} }
} }

View File

@ -6,7 +6,9 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/appleboy/gorush/core"
"github.com/appleboy/gorush/gorush" "github.com/appleboy/gorush/gorush"
"github.com/appleboy/gorush/logx"
"github.com/appleboy/gorush/rpc/proto" "github.com/appleboy/gorush/rpc/proto"
"google.golang.org/grpc" "google.golang.org/grpc"
@ -70,7 +72,7 @@ func (s *Server) Send(ctx context.Context, in *proto.NotificationRequest) (*prot
notification.Badge = &badge notification.Badge = &badge
} }
if in.Topic != "" && in.Platform == gorush.PlatFormAndroid { if in.Topic != "" && in.Platform == core.PlatFormAndroid {
notification.To = in.Topic notification.To = in.Topic
} }
@ -107,7 +109,7 @@ func (s *Server) Send(ctx context.Context, in *proto.NotificationRequest) (*prot
// RunGRPCServer run gorush grpc server // RunGRPCServer run gorush grpc server
func RunGRPCServer(ctx context.Context) error { func RunGRPCServer(ctx context.Context) error {
if !gorush.PushConf.GRPC.Enabled { if !gorush.PushConf.GRPC.Enabled {
gorush.LogAccess.Info("gRPC server is disabled.") logx.LogAccess.Info("gRPC server is disabled.")
return nil return nil
} }
@ -121,19 +123,19 @@ func RunGRPCServer(ctx context.Context) error {
lis, err := net.Listen("tcp", ":"+gorush.PushConf.GRPC.Port) lis, err := net.Listen("tcp", ":"+gorush.PushConf.GRPC.Port)
if err != nil { if err != nil {
gorush.LogError.Fatalln(err) logx.LogError.Fatalln(err)
return err return err
} }
gorush.LogAccess.Info("gRPC server is running on " + gorush.PushConf.GRPC.Port + " port.") logx.LogAccess.Info("gRPC server is running on " + gorush.PushConf.GRPC.Port + " port.")
go func() { go func() {
select { select {
case <-ctx.Done(): case <-ctx.Done():
s.GracefulStop() // graceful shutdown s.GracefulStop() // graceful shutdown
gorush.LogAccess.Info("shutdown the gRPC server") logx.LogAccess.Info("shutdown the gRPC server")
} }
}() }()
if err = s.Serve(lis); err != nil { if err = s.Serve(lis); err != nil {
gorush.LogError.Fatalln(err) logx.LogError.Fatalln(err)
} }
return err return err
} }

View File

@ -5,6 +5,7 @@ import (
"testing" "testing"
"github.com/appleboy/gorush/gorush" "github.com/appleboy/gorush/gorush"
"github.com/appleboy/gorush/logx"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/connectivity" "google.golang.org/grpc/connectivity"
@ -14,7 +15,12 @@ const gRPCAddr = "localhost:9000"
func TestGracefulShutDownGRPCServer(t *testing.T) { func TestGracefulShutDownGRPCServer(t *testing.T) {
// server configs // server configs
gorush.InitLog() logx.InitLog(
gorush.PushConf.Log.AccessLevel,
gorush.PushConf.Log.AccessLog,
gorush.PushConf.Log.ErrorLevel,
gorush.PushConf.Log.ErrorLog,
)
gorush.PushConf.GRPC.Enabled = true gorush.PushConf.GRPC.Enabled = true
gorush.PushConf.GRPC.Port = "9000" gorush.PushConf.GRPC.Port = "9000"
gorush.PushConf.Log.Format = "json" gorush.PushConf.Log.Format = "json"