log/http.go

169 lines
3.8 KiB
Go

// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package log
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
// HTTPLogger implements LoggerProvider
// it writes messages across HTTP as GETs or POSTs with JSON
type HTTPLogger struct {
WriterLogger
URL string `json:"url"`
Method string `json:"method"`
Header map[string][]string `json:"header"`
}
// NewHTTP creates a new HTTPLogger returning as a LoggerProvider
func NewHTTP() LoggerProvider {
logger := new(HTTPLogger)
logger.Level = TRACE
return logger
}
// Init inits http writer with json config.
func (log *HTTPLogger) Init(jsonconfig string) error {
err := json.Unmarshal([]byte(jsonconfig), log)
if err != nil {
return err
}
if _, err := url.Parse(log.URL); err != nil {
return err
}
if log.Method == "POST" {
log.Header["Content-Type"] = []string{"application/json"}
}
return nil
}
// LogEvent logs the event to HTTP
func (log *HTTPLogger) LogEvent(event *Event) error {
if log.Level > event.level {
return nil
}
if !log.Match(event) {
return nil
}
valueMap := map[string]string{}
t := event.time
if log.Prefix != "" {
valueMap["prefix"] = log.Prefix
}
if log.Flags&LUTC != 0 {
t = t.UTC()
}
if log.Flags&Ldate != 0 {
year, month, day := t.Date()
valueMap["date"] = fmt.Sprintf("%4d/%2d/%2d", year, month, day)
}
if log.Flags&(Ltime|Lmicroseconds) != 0 {
hour, min, sec := t.Clock()
if log.Flags&Lmicroseconds != 0 {
valueMap["time"] = fmt.Sprintf("%2d:%2d:%2d.%6d", hour, min, sec, t.Nanosecond()/1e3)
} else {
valueMap["time"] = fmt.Sprintf("%2d:%2d:%2d", hour, min, sec)
}
}
if log.Flags&(Lshortfile|Llongfile) != 0 {
file := event.filename
if log.Flags&Lmedfile == Lmedfile {
startIndex := len(file) - 20
if startIndex > 0 {
file = "..." + file[startIndex:]
}
} else if log.Flags&Lshortfile != 0 {
startIndex := strings.LastIndexByte(file, '/')
if startIndex > 0 && startIndex < len(file) {
file = file[startIndex+1:]
}
}
valueMap["file"] = file
}
if log.Flags&(Lfuncname|Lshortfuncname) != 0 {
funcname := event.caller
if log.Flags&Lshortfuncname != 0 {
lastIndex := strings.LastIndexByte(funcname, '.')
if lastIndex > 0 && len(funcname) > lastIndex+1 {
funcname = funcname[lastIndex+1:]
}
}
valueMap["funcname"] = funcname
}
if log.Flags&(Llevel|Llevelinitial) != 0 {
level := strings.ToUpper(event.level.String())
if log.Flags&Llevelinitial != 0 {
valueMap["level"] = level[0:1]
} else {
valueMap["level"] = level
}
}
pawMode := allowColor
if !log.Colorize {
pawMode = removeColor
}
buf := make([]byte, 0, len(event.msg))
baw := byteArrayWriter(buf)
(&protectedANSIWriter{
w: &baw,
mode: pawMode,
}).Write([]byte(event.msg))
buf = baw
valueMap["msg"] = string(buf)
if event.stacktrace != "" && log.StacktraceLevel <= event.level {
valueMap["stack"] = event.stacktrace
}
var req *http.Request
if log.Method == "POST" {
jsonBytes, err := json.Marshal(valueMap)
if err != nil {
return err
}
req, err = http.NewRequest(log.Method, log.URL, bytes.NewBuffer(jsonBytes))
if err != nil {
return err
}
} else {
reqURL, _ := url.Parse(log.URL)
query := reqURL.Query()
for key, value := range valueMap {
query.Add(key, value)
}
reqURL.RawQuery = query.Encode()
var err error
req, err = http.NewRequest(log.Method, reqURL.String(), nil)
if err != nil {
return err
}
}
req.Header = log.Header
_, err := http.DefaultClient.Do(req)
return err
}
// Flush does nothing for this implementation
func (log *HTTPLogger) Flush() {
}
// GetName returns the default name for this implementation
func (log *HTTPLogger) GetName() string {
return "http"
}
func init() {
Register("http", NewHTTP)
}