2
0
mirror of https://github.com/dxvgef/tsing synced 2020-06-03 17:11:42 +00:00
tsing/event.go
2020-03-27 23:40:39 +08:00

226 lines
5.2 KiB
Go

package tsing
import (
"errors"
"net/http"
"path/filepath"
"runtime"
"strconv"
"strings"
)
// 事件
type Event struct {
Status int // HTTP状态码
Message error // 消息(error)
Source *_Source // 来源
Trace []string // 跟踪
ResponseWriter http.ResponseWriter
Request *http.Request
}
// 来源信息
type _Source struct {
Func string // 函数名
File string // 文件名
Line int // 行号
}
// 事件处理器
type EventHandler func(*Event)
func (e *Event) reset(resp http.ResponseWriter, req *http.Request) {
e.Message = nil
e.Source = nil
e.Status = 0
e.Trace = nil
e.ResponseWriter = resp
e.Request = req
}
// 处理器返回参数事件
func (engine *Engine) handlerErrorEvent(resp http.ResponseWriter, req *http.Request, source *_Source, err error) {
if err == nil {
return
}
// 从池中取出一个ctx
event := engine.eventPool.Get().(*Event)
event.reset(resp, req)
event.Status = 500
event.Message = err
event.Source = source
if engine.Config.EventTrace {
for skip := 0; ; skip++ {
funcPtr, file, line, ok := runtime.Caller(skip)
if !ok {
break
}
// 使用短路径
if engine.Config.EventShortPath {
file = strings.TrimPrefix(filepath.Clean(file), filepath.Clean(engine.Config.RootPath))
}
event.Trace = append(event.Trace, file+":"+strconv.Itoa(line)+":"+runtime.FuncForPC(funcPtr).Name())
}
}
engine.Config.EventHandler(event)
engine.eventPool.Put(event)
}
// context的Source()触发的的事件处理器
// 能精准记录事件来源信息
func (engine *Engine) contextSourceHandler(resp http.ResponseWriter, req *http.Request, err error) {
if err == nil || engine.Config.EventHandler == nil || !engine.Config.EventHandlerError {
return
}
// 从池中取出一个ctx
event := engine.eventPool.Get().(*Event)
event.reset(resp, req)
event.Status = 500
event.Message = err
// 如果启用了source
if engine.engine.Config.EventSource {
if funcPtr, file, line, ok := runtime.Caller(2); ok {
// 使用短路径
if engine.Config.EventShortPath {
file = strings.TrimPrefix(file, engine.Config.RootPath)
}
if event.Source != nil {
event.Source.File = file
event.Source.Line = line
event.Source.Func = runtime.FuncForPC(funcPtr).Name()
} else {
var source _Source
source.File = file
source.Line = line
source.Func = runtime.FuncForPC(funcPtr).Name()
event.Source = &source
}
}
}
// 如果开启了trace
if engine.Config.EventTrace {
for skip := 0; ; skip++ {
funcPtr, file, line, ok := runtime.Caller(skip)
if !ok {
break
}
// 使用短路径
if engine.Config.EventShortPath {
file = strings.TrimPrefix(file, engine.Config.RootPath)
}
event.Trace = append(event.Trace, file+":"+strconv.Itoa(line)+":"+runtime.FuncForPC(funcPtr).Name())
}
}
engine.Config.EventHandler(event)
engine.eventPool.Put(event)
}
// handler的panic处理器
func (engine *Engine) panicEvent(resp http.ResponseWriter, req *http.Request, err interface{}) {
if !engine.Config.Recover && engine.Config.EventHandler == nil {
return
}
// 从池中取出一个ctx
event := engine.eventPool.Get().(*Event)
event.reset(resp, req)
event.Status = 500
switch t := err.(type) {
case string:
event.Message = errors.New(t)
case error:
event.Message = t
default:
event.Message = errors.New("未知错误消息类型")
}
// 如果启用事件的触发信息
if engine.Config.EventSource {
funcPtr, file, line, ok := runtime.Caller(3)
if ok {
// 缩短文件路径
if engine.Config.EventShortPath {
file = strings.TrimPrefix(file, engine.Config.RootPath)
}
if event.Source != nil {
event.Source.File = file
event.Source.Line = line
event.Source.Func = runtime.FuncForPC(funcPtr).Name()
} else {
var source _Source
source.File = file
source.Line = line
source.Func = runtime.FuncForPC(funcPtr).Name()
event.Source = &source
}
}
}
// 如果启用事件的跟踪信息
if engine.Config.EventTrace {
for skip := 0; ; skip++ {
_, file, line, ok := runtime.Caller(skip)
if !ok {
break
}
// 缩短路径
if engine.Config.EventShortPath {
file = strings.TrimPrefix(file, engine.Config.RootPath)
}
event.Trace = append(event.Trace, file+":"+strconv.Itoa(line))
}
}
engine.Config.EventHandler(event)
// 将event放回池中
engine.eventPool.Put(event)
}
// 404事件处理器
func (engine *Engine) notFoundEvent(resp http.ResponseWriter, req *http.Request) {
if engine.Config.EventHandler == nil {
return
}
// 从池中取出一个ctx
event := engine.eventPool.Get().(*Event)
event.reset(resp, req)
event.Status = http.StatusNotFound
event.Message = errors.New(http.StatusText(http.StatusNotFound))
engine.Config.EventHandler(event)
engine.eventPool.Put(event)
}
// 405事件处理器
func (engine *Engine) methodNotAllowedEvent(resp http.ResponseWriter, req *http.Request) {
if engine.Config.EventHandler == nil {
return
}
// 从池中取出一个ctx
event := engine.eventPool.Get().(*Event)
event.reset(resp, req)
event.Status = http.StatusMethodNotAllowed
event.Message = errors.New(http.StatusText(http.StatusMethodNotAllowed))
engine.Config.EventHandler(event)
engine.eventPool.Put(event)
}