diff --git a/pkg/infrastructure/logs/alils/alils.go b/pkg/infrastructure/logs/alils/alils.go index 02e6f995..03e97045 100644 --- a/pkg/infrastructure/logs/alils/alils.go +++ b/pkg/infrastructure/logs/alils/alils.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/astaxie/beego/pkg/infrastructure/logs" + "github.com/astaxie/beego/pkg/infrastructure/utils" "github.com/gogo/protobuf/proto" ) @@ -32,11 +33,12 @@ type Config struct { // aliLSWriter implements LoggerInterface. // Writes messages in keep-live tcp connection. type aliLSWriter struct { - store *LogStore - group []*LogGroup - withMap bool - groupMap map[string]*LogGroup - lock *sync.Mutex + store *LogStore + group []*LogGroup + withMap bool + groupMap map[string]*LogGroup + lock *sync.Mutex + customFormatter func(*logs.LogMsg) string Config } @@ -48,8 +50,17 @@ func NewAliLS() logs.Logger { } // Init parses config and initializes struct -func (c *aliLSWriter) Init(jsonConfig string) (err error) { +func (c *aliLSWriter) Init(jsonConfig string, opts ...utils.KV) error { + for _, elem := range opts { + if elem.GetKey() == "formatter" { + formatter, err := logs.GetFormatter(elem) + if err != nil { + return err + } + c.customFormatter = formatter + } + } json.Unmarshal([]byte(jsonConfig), c) if c.FlushWhen > CacheSize { @@ -63,11 +74,13 @@ func (c *aliLSWriter) Init(jsonConfig string) (err error) { AccessKeySecret: c.KeySecret, } - c.store, err = prj.GetLogStore(c.LogStore) + store, err := prj.GetLogStore(c.LogStore) if err != nil { return err } + c.store = store + // Create default Log Group c.group = append(c.group, &LogGroup{ Topic: proto.String(""), @@ -100,6 +113,10 @@ func (c *aliLSWriter) Init(jsonConfig string) (err error) { return nil } +func (c *aliLSWriter) Format(lm *logs.LogMsg) string { + return lm.Msg +} + // WriteMsg writes a message in connection. // If connection is down, try to re-connect. func (c *aliLSWriter) WriteMsg(lm *logs.LogMsg) error { @@ -117,20 +134,23 @@ func (c *aliLSWriter) WriteMsg(lm *logs.LogMsg) error { if len(strs) == 2 { pos := strings.LastIndex(strs[0], " ") topic = strs[0][pos+1 : len(strs[0])] - content = strs[0][0:pos] + strs[1] lg = c.groupMap[topic] } // send to empty Topic if lg == nil { - content = lm.Msg lg = c.group[0] } } else { - content = lm.Msg lg = c.group[0] } + if c.customFormatter != nil { + content = c.customFormatter(lm) + } else { + content = c.Format(lm) + } + c1 := &LogContent{ Key: proto.String("msg"), Value: proto.String(content), diff --git a/pkg/infrastructure/logs/conn.go b/pkg/infrastructure/logs/conn.go index e0560fd9..f7d44d7f 100644 --- a/pkg/infrastructure/logs/conn.go +++ b/pkg/infrastructure/logs/conn.go @@ -18,18 +18,21 @@ import ( "encoding/json" "io" "net" + + "github.com/astaxie/beego/pkg/infrastructure/utils" ) // connWriter implements LoggerInterface. // Writes messages in keep-live tcp connection. type connWriter struct { - lg *logWriter - innerWriter io.WriteCloser - ReconnectOnMsg bool `json:"reconnectOnMsg"` - Reconnect bool `json:"reconnect"` - Net string `json:"net"` - Addr string `json:"addr"` - Level int `json:"level"` + lg *logWriter + innerWriter io.WriteCloser + customFormatter func(*LogMsg) string + ReconnectOnMsg bool `json:"reconnectOnMsg"` + Reconnect bool `json:"reconnect"` + Net string `json:"net"` + Addr string `json:"addr"` + Level int `json:"level"` } // NewConn creates new ConnWrite returning as LoggerInterface. @@ -39,9 +42,24 @@ func NewConn() Logger { return conn } +func (c *connWriter) Format(lm *LogMsg) string { + return lm.Msg +} + // Init initializes a connection writer with json config. // json config only needs they "level" key -func (c *connWriter) Init(jsonConfig string) error { +func (c *connWriter) Init(jsonConfig string, opts ...utils.KV) error { + + for _, elem := range opts { + if elem.GetKey() == "formatter" { + formatter, err := GetFormatter(elem) + if err != nil { + return err + } + c.customFormatter = formatter + } + } + return json.Unmarshal([]byte(jsonConfig), c) } @@ -62,7 +80,15 @@ func (c *connWriter) WriteMsg(lm *LogMsg) error { defer c.innerWriter.Close() } - _, err := c.lg.writeln(lm) + msg := "" + if c.customFormatter != nil { + msg = c.customFormatter(lm) + } else { + msg = c.Format(lm) + + } + + _, err := c.lg.writeln(msg) if err != nil { return err } diff --git a/pkg/infrastructure/logs/console.go b/pkg/infrastructure/logs/console.go index 024152aa..802d79f5 100644 --- a/pkg/infrastructure/logs/console.go +++ b/pkg/infrastructure/logs/console.go @@ -19,6 +19,8 @@ import ( "os" "strings" + "github.com/astaxie/beego/pkg/infrastructure/utils" + "github.com/shiena/ansicolor" ) @@ -47,9 +49,20 @@ var colors = []brush{ // consoleWriter implements LoggerInterface and writes messages to terminal. type consoleWriter struct { - lg *logWriter - Level int `json:"level"` - Colorful bool `json:"color"` //this filed is useful only when system's terminal supports color + lg *logWriter + customFormatter func(*LogMsg) string + Level int `json:"level"` + Colorful bool `json:"color"` //this filed is useful only when system's terminal supports color +} + +func (c *consoleWriter) Format(lm *LogMsg) string { + msg := lm.Msg + + h, _, _ := formatTimeHeader(lm.When) + bytes := append(append(h, msg...), '\n') + + return string(bytes) + } // NewConsole creates ConsoleWriter returning as LoggerInterface. @@ -64,10 +77,22 @@ func NewConsole() Logger { // Init initianlizes the console logger. // jsonConfig must be in the format '{"level":LevelTrace}' -func (c *consoleWriter) Init(jsonConfig string) error { +func (c *consoleWriter) Init(jsonConfig string, opts ...utils.KV) error { + + for _, elem := range opts { + if elem.GetKey() == "formatter" { + formatter, err := GetFormatter(elem) + if err != nil { + return err + } + c.customFormatter = formatter + } + } + if len(jsonConfig) == 0 { return nil } + return json.Unmarshal([]byte(jsonConfig), c) } @@ -76,10 +101,21 @@ func (c *consoleWriter) WriteMsg(lm *LogMsg) error { if lm.Level > c.Level { return nil } + + msg := "" + if c.Colorful { lm.Msg = strings.Replace(lm.Msg, levelPrefix[lm.Level], colors[lm.Level](levelPrefix[lm.Level]), 1) } - c.lg.writeln(lm) + + if c.customFormatter != nil { + msg = c.customFormatter(lm) + } else { + msg = c.Format(lm) + + } + + c.lg.writeln(msg) return nil } diff --git a/pkg/infrastructure/logs/es/es.go b/pkg/infrastructure/logs/es/es.go index c2631584..857a1a34 100644 --- a/pkg/infrastructure/logs/es/es.go +++ b/pkg/infrastructure/logs/es/es.go @@ -13,6 +13,7 @@ import ( "github.com/elastic/go-elasticsearch/v6/esapi" "github.com/astaxie/beego/pkg/infrastructure/logs" + "github.com/astaxie/beego/pkg/infrastructure/utils" ) // NewES returns a LoggerInterface @@ -31,13 +32,29 @@ func NewES() logs.Logger { // import _ "github.com/astaxie/beego/logs/es" type esLogger struct { *elasticsearch.Client - DSN string `json:"dsn"` - Level int `json:"level"` + DSN string `json:"dsn"` + Level int `json:"level"` + customFormatter func(*logs.LogMsg) string +} + +func (el *esLogger) Format(lm *logs.LogMsg) string { + return lm.Msg } // {"dsn":"http://localhost:9200/","level":1} -func (el *esLogger) Init(jsonconfig string) error { - err := json.Unmarshal([]byte(jsonconfig), el) +func (el *esLogger) Init(jsonConfig string, opts ...utils.KV) error { + + for _, elem := range opts { + if elem.GetKey() == "formatter" { + formatter, err := logs.GetFormatter(elem) + if err != nil { + return err + } + el.customFormatter = formatter + } + } + + err := json.Unmarshal([]byte(jsonConfig), el) if err != nil { return err } @@ -65,9 +82,16 @@ func (el *esLogger) WriteMsg(lm *logs.LogMsg) error { return nil } + msg := "" + if el.customFormatter != nil { + msg = el.customFormatter(lm) + } else { + msg = el.Format(lm) + } + idx := LogDocument{ Timestamp: lm.When.Format(time.RFC3339), - Msg: lm.Msg, + Msg: msg, } body, err := json.Marshal(idx) diff --git a/pkg/infrastructure/logs/file.go b/pkg/infrastructure/logs/file.go index 23ea4b09..0c96918c 100644 --- a/pkg/infrastructure/logs/file.go +++ b/pkg/infrastructure/logs/file.go @@ -27,6 +27,8 @@ import ( "strings" "sync" "time" + + "github.com/astaxie/beego/pkg/infrastructure/utils" ) // fileLogWriter implements LoggerInterface. @@ -60,6 +62,8 @@ type fileLogWriter struct { hourlyOpenDate int hourlyOpenTime time.Time + customFormatter func(*LogMsg) string + Rotate bool `json:"rotate"` Level int `json:"level"` @@ -89,6 +93,10 @@ func newFileWriter() Logger { return w } +func (w *fileLogWriter) Format(lm *LogMsg) string { + return lm.Msg +} + // Init file logger with json config. // jsonConfig like: // { @@ -100,7 +108,18 @@ func newFileWriter() Logger { // "rotate":true, // "perm":"0600" // } -func (w *fileLogWriter) Init(jsonConfig string) error { +func (w *fileLogWriter) Init(jsonConfig string, opts ...utils.KV) error { + + for _, elem := range opts { + if elem.GetKey() == "formatter" { + formatter, err := GetFormatter(elem) + if err != nil { + return err + } + w.customFormatter = formatter + } + } + err := json.Unmarshal([]byte(jsonConfig), w) if err != nil { return err @@ -149,7 +168,15 @@ func (w *fileLogWriter) WriteMsg(lm *LogMsg) error { return nil } hd, d, h := formatTimeHeader(lm.When) - lm.Msg = string(hd) + lm.Msg + "\n" + msg := "" + + if w.customFormatter != nil { + msg = w.customFormatter(lm) + } else { + msg = w.Format(lm) + } + + msg = fmt.Sprintf("%s %s\n", string(hd), msg) if w.Rotate { w.RLock() if w.needRotateHourly(len(lm.Msg), h) { @@ -176,10 +203,10 @@ func (w *fileLogWriter) WriteMsg(lm *LogMsg) error { } w.Lock() - _, err := w.fileWriter.Write([]byte(lm.Msg)) + _, err := w.fileWriter.Write([]byte(msg)) if err == nil { w.maxLinesCurLines++ - w.maxSizeCurSize += len(lm.Msg) + w.maxSizeCurSize += len(msg) } w.Unlock() return err @@ -302,7 +329,7 @@ func (w *fileLogWriter) doRotate(logTime time.Time) error { _, err = os.Lstat(w.Filename) if err != nil { - //even if the file is not exist or other ,we should RESTART the logger + // even if the file is not exist or other ,we should RESTART the logger goto RESTART_LOGGER } diff --git a/pkg/infrastructure/logs/jianliao.go b/pkg/infrastructure/logs/jianliao.go index 0e7cfab4..88750125 100644 --- a/pkg/infrastructure/logs/jianliao.go +++ b/pkg/infrastructure/logs/jianliao.go @@ -5,16 +5,19 @@ import ( "fmt" "net/http" "net/url" + + "github.com/astaxie/beego/pkg/infrastructure/utils" ) // JLWriter implements beego LoggerInterface and is used to send jiaoliao webhook type JLWriter struct { - AuthorName string `json:"authorname"` - Title string `json:"title"` - WebhookURL string `json:"webhookurl"` - RedirectURL string `json:"redirecturl,omitempty"` - ImageURL string `json:"imageurl,omitempty"` - Level int `json:"level"` + AuthorName string `json:"authorname"` + Title string `json:"title"` + WebhookURL string `json:"webhookurl"` + RedirectURL string `json:"redirecturl,omitempty"` + ImageURL string `json:"imageurl,omitempty"` + Level int `json:"level"` + customFormatter func(*LogMsg) string } // newJLWriter creates jiaoliao writer. @@ -23,8 +26,22 @@ func newJLWriter() Logger { } // Init JLWriter with json config string -func (s *JLWriter) Init(jsonconfig string) error { - return json.Unmarshal([]byte(jsonconfig), s) +func (s *JLWriter) Init(jsonConfig string, opts ...utils.KV) error { + for _, elem := range opts { + if elem.GetKey() == "formatter" { + formatter, err := GetFormatter(elem) + if err != nil { + return err + } + s.customFormatter = formatter + } + } + + return json.Unmarshal([]byte(jsonConfig), s) +} + +func (s *JLWriter) Format(lm *LogMsg) string { + return lm.Msg } // WriteMsg writes message in smtp writer. @@ -34,7 +51,14 @@ func (s *JLWriter) WriteMsg(lm *LogMsg) error { return nil } - text := fmt.Sprintf("%s %s", lm.When.Format("2006-01-02 15:04:05"), lm.Msg) + text := "" + + if s.customFormatter != nil { + text = fmt.Sprintf("%s %s", lm.When.Format("2006-01-02 15:04:05"), s.customFormatter(lm)) + } else { + text = fmt.Sprintf("%s %s", lm.When.Format("2006-01-02 15:04:05"), s.Format(lm)) + + } form := url.Values{} form.Add("authorName", s.AuthorName) diff --git a/pkg/infrastructure/logs/log.go b/pkg/infrastructure/logs/log.go index 37421625..2d400eba 100644 --- a/pkg/infrastructure/logs/log.go +++ b/pkg/infrastructure/logs/log.go @@ -38,10 +38,13 @@ import ( "log" "os" "path" + "reflect" "runtime" "strings" "sync" "time" + + "github.com/astaxie/beego/pkg/infrastructure/utils" ) // RFC5424 log message levels. @@ -84,8 +87,9 @@ type newLoggerFunc func() Logger // Logger defines the behavior of a log provider. type Logger interface { - Init(config string) error + Init(config string, opts ...utils.KV) error WriteMsg(lm *LogMsg) error + Format(lm *LogMsg) string Destroy() Flush() } @@ -114,6 +118,7 @@ type BeeLogger struct { init bool enableFuncCallDepth bool loggerFuncCallDepth int + globalFormatter func(*LogMsg) string enableFullFilePath bool asynchronous bool prefix string @@ -139,6 +144,10 @@ type LogMsg struct { LineNumber int } +type LogFormatter interface { + Format(lm *LogMsg) string +} + var logMsgPool *sync.Pool // NewLogger returns a new BeeLogger. @@ -179,6 +188,10 @@ func (bl *BeeLogger) Async(msgLen ...int64) *BeeLogger { return bl } +func Format(lm *LogMsg) string { + return lm.Msg +} + // SetLogger provides a given logger adapter into BeeLogger with config string. // config must in in JSON format like {"interval":360}} func (bl *BeeLogger) setLogger(adapterName string, configs ...string) error { @@ -195,7 +208,16 @@ func (bl *BeeLogger) setLogger(adapterName string, configs ...string) error { } lg := logAdapter() - err := lg.Init(config) + var err error + + // Global formatter overrides the default set formatter + // but not adapter specific formatters set with logs.SetLoggerWithOpts() + if bl.globalFormatter != nil { + err = lg.Init(config, &utils.SimpleKV{Key: "formatter", Value: bl.globalFormatter}) + } else { + err = lg.Init(config) + } + if err != nil { fmt.Fprintln(os.Stderr, "logs.BeeLogger.SetLogger: "+err.Error()) return err @@ -299,7 +321,7 @@ func (bl *BeeLogger) writeMsg(lm *LogMsg, v ...interface{}) error { lm.Msg = fmt.Sprintf("[%s:%d] %s", lm.FilePath, lm.LineNumber, lm.Msg) } - //set level info in front of filename info + // set level info in front of filename info if lm.Level == levelLoggerImpl { // set to emergency to ensure all log will be print out correctly lm.Level = LevelEmergency @@ -382,6 +404,87 @@ func (bl *BeeLogger) startLogger() { } } +// Get the formatter from the opts common.SimpleKV structure +// Looks for a key: "formatter" with value: func(*LogMsg) string +func GetFormatter(opts utils.KV) (func(*LogMsg) string, error) { + if strings.ToLower(opts.GetKey().(string)) == "formatter" { + formatterInterface := reflect.ValueOf(opts.GetValue()).Interface() + formatterFunc := formatterInterface.(func(*LogMsg) string) + return formatterFunc, nil + } + + return nil, fmt.Errorf("no \"formatter\" key given in simpleKV") +} + +// SetLoggerWithOpts sets a log adapter with a user defined logging format. Config must be valid JSON +// such as: {"interval":360} +func (bl *BeeLogger) setLoggerWithOpts(adapterName string, opts utils.KV, configs ...string) error { + config := append(configs, "{}")[0] + for _, l := range bl.outputs { + if l.name == adapterName { + return fmt.Errorf("logs: duplicate adaptername %q (you have set this logger before)", adapterName) + } + } + + logAdapter, ok := adapters[adapterName] + if !ok { + return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName) + } + + if opts.GetKey() == nil { + return fmt.Errorf("No SimpleKV struct set for %s log adapter", adapterName) + } + + lg := logAdapter() + err := lg.Init(config, opts) + if err != nil { + fmt.Fprintln(os.Stderr, "logs.BeeLogger.SetLogger: "+err.Error()) + return err + } + + bl.outputs = append(bl.outputs, &nameLogger{ + name: adapterName, + Logger: lg, + }) + + return nil +} + +// SetLogger provides a given logger adapter into BeeLogger with config string. +func (bl *BeeLogger) SetLoggerWithOpts(adapterName string, opts utils.KV, configs ...string) error { + bl.lock.Lock() + defer bl.lock.Unlock() + if !bl.init { + bl.outputs = []*nameLogger{} + bl.init = true + } + return bl.setLoggerWithOpts(adapterName, opts, configs...) +} + +// SetLoggerWIthOpts sets a given log adapter with a custom log adapter. +// Log Adapter must be given in the form common.SimpleKV{Key: "formatter": Value: struct.FormatFunc} +// where FormatFunc has the signature func(*LogMsg) string +// func SetLoggerWithOpts(adapter string, config []string, formatterFunc func(*LogMsg) string) error { +func SetLoggerWithOpts(adapter string, config []string, opts utils.KV) error { + err := beeLogger.SetLoggerWithOpts(adapter, opts, config...) + if err != nil { + log.Fatal(err) + } + return nil + +} + +func (bl *BeeLogger) setGlobalFormatter(fmtter func(*LogMsg) string) error { + bl.globalFormatter = fmtter + return nil +} + +// SetGlobalFormatter sets the global formatter for all log adapters +// This overrides and other individually set adapter +func SetGlobalFormatter(fmtter func(*LogMsg) string) error { + return beeLogger.setGlobalFormatter(fmtter) +} + // Emergency Log EMERGENCY level message. func (bl *BeeLogger) Emergency(format string, v ...interface{}) { if LevelEmergency > bl.level { @@ -777,9 +880,9 @@ func formatLog(f interface{}, v ...interface{}) string { return msg } if strings.Contains(msg, "%") && !strings.Contains(msg, "%%") { - //format string + // format string } else { - //do not contain format char + // do not contain format char msg += strings.Repeat(" %v", len(v)) } default: diff --git a/pkg/infrastructure/logs/log_formatter_test.go b/pkg/infrastructure/logs/log_formatter_test.go new file mode 100644 index 00000000..73281cf6 --- /dev/null +++ b/pkg/infrastructure/logs/log_formatter_test.go @@ -0,0 +1,35 @@ +package logs + +import ( + "fmt" + "testing" + + "github.com/astaxie/beego/pkg/infrastructure/utils" +) + +func customFormatter(lm *LogMsg) string { + return fmt.Sprintf("[CUSTOM CONSOLE LOGGING] %s", lm.Msg) +} + +func globalFormatter(lm *LogMsg) string { + return fmt.Sprintf("[GLOBAL] %s", lm.Msg) +} + +func TestCustomLoggingFormatter(t *testing.T) { + // beego.BConfig.Log.AccessLogs = true + + SetLoggerWithOpts("console", []string{`{"color":true}`}, &utils.SimpleKV{Key: "formatter", Value: customFormatter}) + + // Message will be formatted by the customFormatter with colorful text set to true + Informational("Test message") +} + +func TestGlobalLoggingFormatter(t *testing.T) { + SetGlobalFormatter(globalFormatter) + + SetLogger("console", `{"color":true}`) + + // Message will be formatted by globalFormatter + Informational("Test message") + +} diff --git a/pkg/infrastructure/logs/logger.go b/pkg/infrastructure/logs/logger.go index 721c8dc1..d8b334d4 100644 --- a/pkg/infrastructure/logs/logger.go +++ b/pkg/infrastructure/logs/logger.go @@ -30,10 +30,10 @@ func newLogWriter(wr io.Writer) *logWriter { return &logWriter{writer: wr} } -func (lg *logWriter) writeln(lm *LogMsg) (int, error) { +func (lg *logWriter) writeln(msg string) (int, error) { lg.Lock() - h, _, _ := formatTimeHeader(lm.When) - n, err := lg.writer.Write(append(append(h, lm.Msg...), '\n')) + msg += "\n" + n, err := lg.writer.Write([]byte(msg)) lg.Unlock() return n, err } diff --git a/pkg/infrastructure/logs/multifile.go b/pkg/infrastructure/logs/multifile.go index 1cd9e9f8..bf589b91 100644 --- a/pkg/infrastructure/logs/multifile.go +++ b/pkg/infrastructure/logs/multifile.go @@ -16,6 +16,8 @@ package logs import ( "encoding/json" + + "github.com/astaxie/beego/pkg/infrastructure/utils" ) // A filesLogWriter manages several fileLogWriter @@ -24,9 +26,10 @@ import ( // and write the error-level logs to project.error.log and write the debug-level logs to project.debug.log // the rotate attribute also acts like fileLogWriter type multiFileLogWriter struct { - writers [LevelDebug + 1 + 1]*fileLogWriter // the last one for fullLogWriter - fullLogWriter *fileLogWriter - Separate []string `json:"separate"` + writers [LevelDebug + 1 + 1]*fileLogWriter // the last one for fullLogWriter + fullLogWriter *fileLogWriter + Separate []string `json:"separate"` + customFormatter func(*LogMsg) string } var levelNames = [...]string{"emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"} @@ -44,9 +47,19 @@ var levelNames = [...]string{"emergency", "alert", "critical", "error", "warning // "separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"], // } -func (f *multiFileLogWriter) Init(config string) error { +func (f *multiFileLogWriter) Init(jsonConfig string, opts ...utils.KV) error { + for _, elem := range opts { + if elem.GetKey() == "formatter" { + formatter, err := GetFormatter(elem) + if err != nil { + return err + } + f.customFormatter = formatter + } + } + writer := newFileWriter().(*fileLogWriter) - err := writer.Init(config) + err := writer.Init(jsonConfig) if err != nil { return err } @@ -54,10 +67,10 @@ func (f *multiFileLogWriter) Init(config string) error { f.writers[LevelDebug+1] = writer //unmarshal "separate" field to f.Separate - json.Unmarshal([]byte(config), f) + json.Unmarshal([]byte(jsonConfig), f) jsonMap := map[string]interface{}{} - json.Unmarshal([]byte(config), &jsonMap) + json.Unmarshal([]byte(jsonConfig), &jsonMap) for i := LevelEmergency; i < LevelDebug+1; i++ { for _, v := range f.Separate { @@ -74,10 +87,13 @@ func (f *multiFileLogWriter) Init(config string) error { } } } - return nil } +func (f *multiFileLogWriter) Format(lm *LogMsg) string { + return lm.Msg +} + func (f *multiFileLogWriter) Destroy() { for i := 0; i < len(f.writers); i++ { if f.writers[i] != nil { diff --git a/pkg/infrastructure/logs/slack.go b/pkg/infrastructure/logs/slack.go index dad4f4ea..d56b9acd 100644 --- a/pkg/infrastructure/logs/slack.go +++ b/pkg/infrastructure/logs/slack.go @@ -5,12 +5,16 @@ import ( "fmt" "net/http" "net/url" + + "github.com/astaxie/beego/pkg/infrastructure/utils" ) // SLACKWriter implements beego LoggerInterface and is used to send jiaoliao webhook type SLACKWriter struct { - WebhookURL string `json:"webhookurl"` - Level int `json:"level"` + WebhookURL string `json:"webhookurl"` + Level int `json:"level"` + UseCustomFormatter bool + CustomFormatter func(*LogMsg) string } // newSLACKWriter creates jiaoliao writer. @@ -18,9 +22,19 @@ func newSLACKWriter() Logger { return &SLACKWriter{Level: LevelTrace} } +func (s *SLACKWriter) Format(lm *LogMsg) string { + return lm.Msg +} + // Init SLACKWriter with json config string -func (s *SLACKWriter) Init(jsonconfig string) error { - return json.Unmarshal([]byte(jsonconfig), s) +func (s *SLACKWriter) Init(jsonConfig string, opts ...utils.KV) error { + // if elem != nil { + // s.UseCustomFormatter = true + // s.CustomFormatter = elem + // } + // } + + return json.Unmarshal([]byte(jsonConfig), s) } // WriteMsg write message in smtp writer. @@ -29,8 +43,8 @@ func (s *SLACKWriter) WriteMsg(lm *LogMsg) error { if lm.Level > s.Level { return nil } - - text := fmt.Sprintf("{\"text\": \"%s %s\"}", lm.When.Format("2006-01-02 15:04:05"), lm.Msg) + msg := s.Format(lm) + text := fmt.Sprintf("{\"text\": \"%s %s\"}", lm.When.Format("2006-01-02 15:04:05"), msg) form := url.Values{} form.Add("payload", text) diff --git a/pkg/infrastructure/logs/smtp.go b/pkg/infrastructure/logs/smtp.go index 0d2b3c29..904a89df 100644 --- a/pkg/infrastructure/logs/smtp.go +++ b/pkg/infrastructure/logs/smtp.go @@ -21,6 +21,8 @@ import ( "net" "net/smtp" "strings" + + "github.com/astaxie/beego/pkg/infrastructure/utils" ) // SMTPWriter implements LoggerInterface and is used to send emails via given SMTP-server. @@ -32,6 +34,7 @@ type SMTPWriter struct { FromAddress string `json:"fromAddress"` RecipientAddresses []string `json:"sendTos"` Level int `json:"level"` + customFormatter func(*LogMsg) string } // NewSMTPWriter creates the smtp writer. @@ -50,8 +53,19 @@ func newSMTPWriter() Logger { // "sendTos":["email1","email2"], // "level":LevelError // } -func (s *SMTPWriter) Init(jsonconfig string) error { - return json.Unmarshal([]byte(jsonconfig), s) +func (s *SMTPWriter) Init(jsonConfig string, opts ...utils.KV) error { + + for _, elem := range opts { + if elem.GetKey() == "formatter" { + formatter, err := GetFormatter(elem) + if err != nil { + return err + } + s.customFormatter = formatter + } + } + + return json.Unmarshal([]byte(jsonConfig), s) } func (s *SMTPWriter) getSMTPAuth(host string) smtp.Auth { @@ -114,6 +128,10 @@ func (s *SMTPWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAd return client.Quit() } +func (s *SMTPWriter) Format(lm *LogMsg) string { + return lm.Msg +} + // WriteMsg writes message in smtp writer. // Sends an email with subject and only this message. func (s *SMTPWriter) WriteMsg(lm *LogMsg) error { @@ -126,11 +144,13 @@ func (s *SMTPWriter) WriteMsg(lm *LogMsg) error { // Set up authentication information. auth := s.getSMTPAuth(hp[0]) + msg := s.Format(lm) + // Connect to the server, authenticate, set the sender and recipient, // and send the email all in one step. contentType := "Content-Type: text/plain" + "; charset=UTF-8" mailmsg := []byte("To: " + strings.Join(s.RecipientAddresses, ";") + "\r\nFrom: " + s.FromAddress + "<" + s.FromAddress + - ">\r\nSubject: " + s.Subject + "\r\n" + contentType + "\r\n\r\n" + fmt.Sprintf(".%s", lm.When.Format("2006-01-02 15:04:05")) + lm.Msg) + ">\r\nSubject: " + s.Subject + "\r\n" + contentType + "\r\n\r\n" + fmt.Sprintf(".%s", lm.When.Format("2006-01-02 15:04:05")) + msg) return s.sendMail(s.Host, auth, s.FromAddress, s.RecipientAddresses, mailmsg) }