From 40c9ea1596848b34cf10b8c118e39878acc2cfcd Mon Sep 17 00:00:00 2001 From: c9s Date: Mon, 13 Jul 2020 12:34:15 +0800 Subject: [PATCH] move out slack components to the slack pkg --- bbgo/accounting.go | 7 +++ bbgo/trader.go | 134 +------------------------------------------ slack/logrus_look.go | 57 ++++++++++++++++++ slack/notifier.go | 87 ++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 132 deletions(-) create mode 100644 bbgo/accounting.go create mode 100644 slack/logrus_look.go create mode 100644 slack/notifier.go diff --git a/bbgo/accounting.go b/bbgo/accounting.go new file mode 100644 index 000000000..1d4b3e2fa --- /dev/null +++ b/bbgo/accounting.go @@ -0,0 +1,7 @@ +package bbgo + +import "github.com/leekchan/accounting" + +var USD = accounting.Accounting{Symbol: "$ ", Precision: 2} +var BTC = accounting.Accounting{Symbol: "BTC ", Precision: 8} + diff --git a/bbgo/trader.go b/bbgo/trader.go index 6f0dbe97b..bc6f8636a 100644 --- a/bbgo/trader.go +++ b/bbgo/trader.go @@ -2,146 +2,16 @@ package bbgo import ( "context" - "fmt" - "time" - - "github.com/leekchan/accounting" + slack2 "github.com/c9s/bbgo/pkg/slack" log "github.com/sirupsen/logrus" "github.com/slack-go/slack" "github.com/c9s/bbgo/pkg/bbgo/exchange/binance" "github.com/c9s/bbgo/pkg/bbgo/types" - "github.com/c9s/bbgo/pkg/slack/slackstyle" - "github.com/c9s/bbgo/pkg/util" ) -var USD = accounting.Accounting{Symbol: "$ ", Precision: 2} -var BTC = accounting.Accounting{Symbol: "BTC ", Precision: 8} - -type SlackLogHook struct { - Slack *slack.Client - ErrorChannel string -} - -func (t *SlackLogHook) Levels() []log.Level { - return []log.Level{ - // log.InfoLevel, - log.ErrorLevel, - log.PanicLevel, - // log.WarnLevel, - } -} - -func (t *SlackLogHook) Fire(e *log.Entry) error { - var color = "#F0F0F0" - - switch e.Level { - case log.DebugLevel: - color = "#9B30FF" - case log.InfoLevel: - color = "good" - case log.ErrorLevel, log.FatalLevel, log.PanicLevel: - color = "danger" - default: - color = "warning" - } - - var slackAttachments []slack.Attachment = nil - - logerr, ok := e.Data["err"] - if ok { - slackAttachments = append(slackAttachments, slack.Attachment{ - Color: color, - Title: "Error", - Fields: []slack.AttachmentField{ - {Title: "Error", Value: logerr.(error).Error()}, - }, - }) - } - - _, _, err := t.Slack.PostMessageContext(context.Background(), t.ErrorChannel, - slack.MsgOptionText(e.Message, true), - slack.MsgOptionAttachments(slackAttachments...)) - - return err -} - - -type SlackNotifier struct { - Slack *slack.Client - - TradingChannel string - ErrorChannel string - InfoChannel string -} - - -func (t *SlackNotifier) Infof(format string, args ...interface{}) { - var slackAttachments []slack.Attachment = nil - var slackArgsStartIdx = -1 - for idx, arg := range args { - switch a := arg.(type) { - - // concrete type assert first - case slack.Attachment: - if slackArgsStartIdx == -1 { - slackArgsStartIdx = idx - } - slackAttachments = append(slackAttachments, a) - - case slackstyle.SlackAttachmentCreator: - if slackArgsStartIdx == -1 { - slackArgsStartIdx = idx - } - slackAttachments = append(slackAttachments, a.SlackAttachment()) - - } - } - - var nonSlackArgs = []interface{}{} - if slackArgsStartIdx > 0 { - nonSlackArgs = args[:slackArgsStartIdx] - } - - log.Infof(format, nonSlackArgs...) - - _, _, err := t.Slack.PostMessageContext(context.Background(), t.InfoChannel, - slack.MsgOptionText(fmt.Sprintf(format, nonSlackArgs...), true), - slack.MsgOptionAttachments(slackAttachments...)) - if err != nil { - log.WithError(err).Errorf("slack error: %s", err.Error()) - } -} - -func (t *SlackNotifier) ReportTrade(trade *types.Trade) { - _, _, err := t.Slack.PostMessageContext(context.Background(), t.TradingChannel, - slack.MsgOptionText(util.Render(`:handshake: trade execution @ {{ .Price }}`, trade), true), - slack.MsgOptionAttachments(trade.SlackAttachment())) - - if err != nil { - log.WithError(err).Error("slack send error") - } -} - -func (t *SlackNotifier) ReportPnL(report *ProfitAndLossReport) { - attachment := report.SlackAttachment() - - _, _, err := t.Slack.PostMessageContext(context.Background(), t.TradingChannel, - slack.MsgOptionText(util.Render( - `:heavy_dollar_sign: Here is your *{{ .symbol }}* PnL report collected since *{{ .startTime }}*`, - map[string]interface{}{ - "symbol": report.Symbol, - "startTime": report.StartTime.Format(time.RFC822), - }), true), - slack.MsgOptionAttachments(attachment)) - - if err != nil { - log.WithError(err).Errorf("slack send error") - } -} - type Trader struct { - Notifier *SlackNotifier + Notifier *slack2.SlackNotifier // Context is trading Context Context *TradingContext diff --git a/slack/logrus_look.go b/slack/logrus_look.go new file mode 100644 index 000000000..29c383ebe --- /dev/null +++ b/slack/logrus_look.go @@ -0,0 +1,57 @@ +package slack + +import ( + "context" + "github.com/sirupsen/logrus" + "github.com/slack-go/slack" +) + +type SlackLogHook struct { + Slack *slack.Client + ErrorChannel string +} + +func (t *SlackLogHook) Levels() []logrus.Level { + return []logrus.Level{ + // log.InfoLevel, + logrus.ErrorLevel, + logrus.PanicLevel, + // log.WarnLevel, + } +} + +func (t *SlackLogHook) Fire(e *logrus.Entry) error { + var color = "#F0F0F0" + + switch e.Level { + case logrus.DebugLevel: + color = "#9B30FF" + case logrus.InfoLevel: + color = "good" + case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel: + color = "danger" + default: + color = "warning" + } + + var slackAttachments []slack.Attachment = nil + + logerr, ok := e.Data["err"] + if ok { + slackAttachments = append(slackAttachments, slack.Attachment{ + Color: color, + Title: "Error", + Fields: []slack.AttachmentField{ + {Title: "Error", Value: logerr.(error).Error()}, + }, + }) + } + + _, _, err := t.Slack.PostMessageContext(context.Background(), t.ErrorChannel, + slack.MsgOptionText(e.Message, true), + slack.MsgOptionAttachments(slackAttachments...)) + + return err +} + + diff --git a/slack/notifier.go b/slack/notifier.go new file mode 100644 index 000000000..24f430fcf --- /dev/null +++ b/slack/notifier.go @@ -0,0 +1,87 @@ +package slack + +import ( + "context" + "fmt" + log "github.com/sirupsen/logrus" + "github.com/slack-go/slack" + "time" + + "github.com/c9s/bbgo/pkg/bbgo" + "github.com/c9s/bbgo/pkg/bbgo/types" + "github.com/c9s/bbgo/pkg/slack/slackstyle" + "github.com/c9s/bbgo/pkg/util" +) + +type SlackNotifier struct { + Slack *slack.Client + + TradingChannel string + ErrorChannel string + InfoChannel string +} + +func (t *SlackNotifier) Infof(format string, args ...interface{}) { + var slackAttachments []slack.Attachment = nil + var slackArgsStartIdx = -1 + for idx, arg := range args { + switch a := arg.(type) { + + // concrete type assert first + case slack.Attachment: + if slackArgsStartIdx == -1 { + slackArgsStartIdx = idx + } + slackAttachments = append(slackAttachments, a) + + case slackstyle.SlackAttachmentCreator: + if slackArgsStartIdx == -1 { + slackArgsStartIdx = idx + } + slackAttachments = append(slackAttachments, a.SlackAttachment()) + + } + } + + var nonSlackArgs = []interface{}{} + if slackArgsStartIdx > 0 { + nonSlackArgs = args[:slackArgsStartIdx] + } + + log.Infof(format, nonSlackArgs...) + + _, _, err := t.Slack.PostMessageContext(context.Background(), t.InfoChannel, + slack.MsgOptionText(fmt.Sprintf(format, nonSlackArgs...), true), + slack.MsgOptionAttachments(slackAttachments...)) + if err != nil { + log.WithError(err).Errorf("slack error: %s", err.Error()) + } +} + +func (t *SlackNotifier) ReportTrade(trade *types.Trade) { + _, _, err := t.Slack.PostMessageContext(context.Background(), t.TradingChannel, + slack.MsgOptionText(util.Render(`:handshake: trade execution @ {{ .Price }}`, trade), true), + slack.MsgOptionAttachments(trade.SlackAttachment())) + + if err != nil { + log.WithError(err).Error("slack send error") + } +} + +func (t *SlackNotifier) ReportPnL(report *bbgo.ProfitAndLossReport) { + attachment := report.SlackAttachment() + + _, _, err := t.Slack.PostMessageContext(context.Background(), t.TradingChannel, + slack.MsgOptionText(util.Render( + `:heavy_dollar_sign: Here is your *{{ .symbol }}* PnL report collected since *{{ .startTime }}*`, + map[string]interface{}{ + "symbol": report.Symbol, + "startTime": report.StartTime.Format(time.RFC822), + }), true), + slack.MsgOptionAttachments(attachment)) + + if err != nil { + log.WithError(err).Errorf("slack send error") + } +} +