mirror of https://github.com/gogits/gogs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
3.0 KiB
163 lines
3.0 KiB
// Copyright 2017 Unknwon |
|
// |
|
// Licensed under the Apache License, Version 2.0 (the "License"): you may |
|
// not use this file except in compliance with the License. You may obtain |
|
// a copy of the License at |
|
// |
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
|
// License for the specific language governing permissions and limitations |
|
// under the License. |
|
|
|
package clog |
|
|
|
import ( |
|
"bytes" |
|
"encoding/json" |
|
"errors" |
|
"fmt" |
|
"io/ioutil" |
|
"net/http" |
|
) |
|
|
|
type slackAttachment struct { |
|
Text string `json:"text"` |
|
Color string `json:"color"` |
|
} |
|
|
|
type slackPayload struct { |
|
Attachments []slackAttachment `json:"attachments"` |
|
} |
|
|
|
const ( |
|
SLACK = "slack" |
|
) |
|
|
|
var slackColors = []string{ |
|
"", // Trace |
|
"#3aa3e3", // Info |
|
"warning", // Warn |
|
"danger", // Error |
|
"#ff0200", // Fatal |
|
} |
|
|
|
type SlackConfig struct { |
|
// Minimum level of messages to be processed. |
|
Level LEVEL |
|
// Buffer size defines how many messages can be queued before hangs. |
|
BufferSize int64 |
|
// Slack webhook URL. |
|
URL string |
|
} |
|
|
|
type slack struct { |
|
Adapter |
|
|
|
url string |
|
} |
|
|
|
func newSlack() Logger { |
|
return &slack{ |
|
Adapter: Adapter{ |
|
quitChan: make(chan struct{}), |
|
}, |
|
} |
|
} |
|
|
|
func (s *slack) Level() LEVEL { return s.level } |
|
|
|
func (s *slack) Init(v interface{}) error { |
|
cfg, ok := v.(SlackConfig) |
|
if !ok { |
|
return ErrConfigObject{"SlackConfig", v} |
|
} |
|
|
|
if !isValidLevel(cfg.Level) { |
|
return ErrInvalidLevel{} |
|
} |
|
s.level = cfg.Level |
|
|
|
if len(cfg.URL) == 0 { |
|
return errors.New("URL cannot be empty") |
|
} |
|
s.url = cfg.URL |
|
|
|
s.msgChan = make(chan *Message, cfg.BufferSize) |
|
return nil |
|
} |
|
|
|
func (s *slack) ExchangeChans(errorChan chan<- error) chan *Message { |
|
s.errorChan = errorChan |
|
return s.msgChan |
|
} |
|
|
|
func buildSlackPayload(msg *Message) (string, error) { |
|
payload := slackPayload{ |
|
Attachments: []slackAttachment{ |
|
{ |
|
Text: msg.Body, |
|
Color: slackColors[msg.Level], |
|
}, |
|
}, |
|
} |
|
p, err := json.Marshal(&payload) |
|
if err != nil { |
|
return "", err |
|
} |
|
return string(p), nil |
|
} |
|
|
|
func (s *slack) write(msg *Message) { |
|
payload, err := buildSlackPayload(msg) |
|
if err != nil { |
|
s.errorChan <- fmt.Errorf("slack.buildSlackPayload: %v", err) |
|
return |
|
} |
|
|
|
resp, err := http.Post(s.url, "application/json", bytes.NewReader([]byte(payload))) |
|
if err != nil { |
|
s.errorChan <- fmt.Errorf("slack: %v", err) |
|
} |
|
defer resp.Body.Close() |
|
|
|
if resp.StatusCode/100 != 2 { |
|
data, _ := ioutil.ReadAll(resp.Body) |
|
s.errorChan <- fmt.Errorf("slack: %s", data) |
|
} |
|
} |
|
|
|
func (s *slack) Start() { |
|
LOOP: |
|
for { |
|
select { |
|
case msg := <-s.msgChan: |
|
s.write(msg) |
|
case <-s.quitChan: |
|
break LOOP |
|
} |
|
} |
|
|
|
for { |
|
if len(s.msgChan) == 0 { |
|
break |
|
} |
|
|
|
s.write(<-s.msgChan) |
|
} |
|
s.quitChan <- struct{}{} // Notify the cleanup is done. |
|
} |
|
|
|
func (s *slack) Destroy() { |
|
s.quitChan <- struct{}{} |
|
<-s.quitChan |
|
|
|
close(s.msgChan) |
|
close(s.quitChan) |
|
} |
|
|
|
func init() { |
|
Register(SLACK, newSlack) |
|
}
|
|
|