[FEATURE REQUEST] Slack Webhooks for Logging
Is your feature request related to a problem? Please describe. I would like to send all the error as well as request logs to a channel in my slack workspace.
Describe the solution you'd like Iris is using golog for logging as of now, we can add custom hooks to the package like logrus has to send the logs to the slack channel whenever a log is created.
Describe alternatives you've considered
I have tried configuring logrus with a hook for slack. Then I used app.Logger().Install() to use that logrus instance but had no luck.
Hello @mintunitish ,
For request logs you can implement a custom accesslog.Formatter like the built'n CSV, JSON and Template.
For Iris' generic Logger (golog) you can implement a custom golog.Formatter, register it with the RegisterFormatter and use with the SetFormat as shown at: https://github.com/kataras/golog/blob/a4da832764ad32eb7a54b39ee5568035f6885a7c/_examples/customize-output/main.go#L10
Hello @mintunitish I've made you an accesslog extension for slack, here is the code (1st, the Iris accesslog slack extension and the 2nd is the usage code):
file: iris/middleware/accesslog/slack.go
package accesslog
import (
"io"
"github.com/slack-go/slack"
)
type Slack struct {
// Client is the underline slack slack.
// This or Token are required.
Client *slack.Client
// Token is the oauth slack client token.
// Read more at: https://api.slack.com/web#authentication.
//
// If Client is not null then this is used to initialize the Slack.Client field.
Token string
// ChannelIDs specifies one or more channel the request logs
// will be printed to.
ChannelIDs []string
// HandleMessage set to true whether the slack formatter
// should just send the log to the slack channel(s) and
// stop printing the log to the accesslog's io.Writer output.
HandleMessage bool
// Template is the underline text template format of the logs.
// Set to a custom one if you want to customize the template (how the text is rended).
Template *Template
}
func (f *Slack) SetOutput(dest io.Writer) {
if f.Client == nil && f.Token == "" {
panic("client or token fields must be provided")
}
if len(f.ChannelIDs) == 0 {
panic("channel ids field is required")
}
if f.Token != "" {
c := slack.New(f.Token)
f.Client = c
}
if f.Template == nil {
f.Template = &Template{}
}
f.Template.SetOutput(dest)
}
func (f *Slack) Format(log *Log) (bool, error) {
text, err := f.Template.LogText(log)
if err != nil {
return false, err
}
for _, channelID := range f.ChannelIDs {
_, _, err := f.Client.PostMessage(
channelID,
slack.MsgOptionText(text, false),
slack.MsgOptionAsUser(true),
)
if err != nil {
return false, err
}
}
return f.HandleMessage, nil
}
file: main.go
package main
import (
"os"
"time"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/middleware/accesslog"
)
var (
token = os.Getenv("SLACK_BOT_TOKEN")
channelID = os.Getenv("SLACK_CHANNEL_ID")
)
func main() {
app := iris.New()
ac := accesslog.New(os.Stdout) // or app.Logger().Printer
ac.LatencyRound = time.Second
ac.SetFormatter(&accesslog.Slack{
Token: token,
ChannelIDs: []string{channelID},
HandleMessage: true,
})
app.UseRouter(ac.Handler)
app.Get("/", index)
app.Listen(":8080")
}
func index(ctx iris.Context) {
if sleepDur := ctx.URLParam("sleep"); sleepDur != "" {
if d, err := time.ParseDuration(sleepDur); err == nil {
time.Sleep(d)
}
}
ctx.WriteString("Index")
}