Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import (
const (
defaultMemory = 32 << 20 // 32 MB
defaultHttpCode = http.StatusOK
// ItemKeyHandleStartTime itemkey name for request handler start time
ItemKeyHandleStartTime = "dotweb.HttpContext.StartTime"
// ItemKeyHandleDuration itemkey name for request handler time duration
ItemKeyHandleDuration = "dotweb.HttpContext.HandleDuration"
)

const (
Expand Down Expand Up @@ -108,7 +112,6 @@ type (
viewData core.ConcurrenceMap
features *xFeatureTools
handler HttpHandle
startTime time.Time
}
)

Expand All @@ -126,7 +129,7 @@ func (ctx *HttpContext) reset(res *Response, r *Request, server *HttpServer, nod
ctx.isEnd = false
ctx.features = FeatureTools
ctx.handler = handler
ctx.startTime = time.Now()
ctx.Items().Set(ItemKeyHandleStartTime, time.Now())
}

//release all field
Expand All @@ -148,7 +151,8 @@ func (ctx *HttpContext) release() {
ctx.viewData = nil
ctx.sessionID = ""
ctx.handler = nil
ctx.startTime = time.Time{}
ctx.Items().Remove(ItemKeyHandleStartTime)
ctx.Items().Remove(ItemKeyHandleDuration)
}

// Context return context.Context
Expand Down
24 changes: 19 additions & 5 deletions core/concurrenceMap.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ package core
import (
"fmt"
"sync"
"time"
)

type (
// ReadonlyMap only support readonly method for map
ReadonlyMap interface {
Get(key string) (value interface{}, exists bool)
GetString(key string) string
GetTimeDuration(key string) time.Duration
GetInt(key string) int
GetUInt64(key string) uint64
Exists(key string) bool
Expand All @@ -20,6 +22,7 @@ type (
ConcurrenceMap interface {
Get(key string) (value interface{}, exists bool)
GetString(key string) string
GetTimeDuration(key string) time.Duration
GetInt(key string) int
GetUInt64(key string) uint64
Exists(key string) bool
Expand Down Expand Up @@ -97,8 +100,8 @@ func (ctx *ItemMap) Once(key string) (value interface{}, exists bool) {
return value, exists
}


// GetString 读取指定key在AppContext中的内容,以string格式输出
// GetString 读取指定key在ConcurrenceMap中的内容,以string格式输出
// 如果不存在key,返回空字符串
func (ctx *ItemMap) GetString(key string) string {
value, exists := ctx.Get(key)
if !exists {
Expand All @@ -107,8 +110,8 @@ func (ctx *ItemMap) GetString(key string) string {
return fmt.Sprint(value)
}


// GetInt 读取指定key在AppContext中的内容,以int格式输出
// GetInt 读取指定key在ConcurrenceMap中的内容,以int格式输出
// 如果不存在key,或者转换失败,返回0
func (ctx *ItemMap) GetInt(key string) int {
value, exists := ctx.Get(key)
if !exists {
Expand All @@ -117,7 +120,8 @@ func (ctx *ItemMap) GetInt(key string) int {
return value.(int)
}

// GetUInt64 读取指定key在AppContext中的内容,以int格式输出
// GetUInt64 读取指定key在ConcurrenceMap中的内容,以uint64格式输出
// 如果不存在key,或者转换失败,返回0
func (ctx *ItemMap) GetUInt64(key string) uint64 {
value, exists := ctx.Get(key)
if !exists {
Expand All @@ -126,6 +130,16 @@ func (ctx *ItemMap) GetUInt64(key string) uint64 {
return value.(uint64)
}

// GetTimeDuration 读取指定key在ConcurrenceMap中的内容,以time.Duration格式输出
// 如果不存在key,或者转换失败,返回0
func (ctx *ItemMap) GetTimeDuration(key string) time.Duration {
timeDuration, err := time.ParseDuration(ctx.GetString(key))
if err != nil {
return 0
}
return timeDuration
}

// Exists check exists key
func (ctx *ItemMap) Exists(key string) bool {
_, exists := ctx.innerMap[key]
Expand Down
11 changes: 10 additions & 1 deletion dotweb.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/devfeel/dotweb/session"
"reflect"
"sync"
"time"
)

type (
Expand Down Expand Up @@ -183,11 +184,19 @@ func (app *DotWeb) Use(m ...Middleware) {
}
}

// UseRequestLog register RequestLog middleware
// UseRequestLog register RequestLogMiddleware
func (app *DotWeb) UseRequestLog() {
app.Use(&RequestLogMiddleware{})
}

// UseTimeoutHook register TimeoutHookMiddleware
func (app *DotWeb) UseTimeoutHook(handler StandardHandle, timeout time.Duration){
app.Use(&TimeoutHookMiddleware{
HookHandle: handler,
TimeoutDuration:timeout,
})
}

// SetExceptionHandle set custom error handler
func (app *DotWeb) SetExceptionHandle(handler ExceptionHandle) {
app.ExceptionHandler = handler
Expand Down
61 changes: 61 additions & 0 deletions example/basemiddleware/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package main

import (
"fmt"
"github.com/devfeel/dotweb"
"strconv"
"time"
)

func main() {
//初始化DotServer
app := dotweb.New()

//设置dotserver日志目录
//如果不设置,默认不启用,且默认为当前目录
app.SetEnabledLog(true)

//开启development模式
app.SetDevelopmentMode()

//启用超时处理,这里设置为3秒
app.UseTimeoutHook(
func(ctx dotweb.Context) {
fmt.Println(ctx.Items().GetTimeDuration(dotweb.ItemKeyHandleDuration)/time.Millisecond)
}, time.Second * 3)
//设置路由
InitRoute(app.HttpServer)

//启动 监控服务
app.SetPProfConfig(true, 8081)

// 开始服务
port := 8080
fmt.Println("dotweb.StartServer => " + strconv.Itoa(port))
err := app.StartServer(port)
fmt.Println("dotweb.StartServer error => ", err)
}

// Index
func Index(ctx dotweb.Context) error {
ctx.Response().Header().Set("Content-Type", "text/html; charset=utf-8")
//fmt.Println(time.Now(), "Index Handler")
err := ctx.WriteString("index => ", ctx.Request().Url())
fmt.Println(ctx.RouterNode().GroupMiddlewares())
return err
}

// Wait10Second
func Wait10Second(ctx dotweb.Context) error{
time.Sleep(time.Second * 10)
ctx.WriteString("HandleDuration:", fmt.Sprint(ctx.Items().Get(dotweb.ItemKeyHandleStartTime)))
return nil
}

func InitRoute(server *dotweb.HttpServer) {
server.Router().GET("/", Index)
server.Router().GET("/index", Index)
server.Router().GET("/wait", Wait10Second)
}


19 changes: 16 additions & 3 deletions framework/convert/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,42 @@ import (
"time"
)

//convert string to []byte
// String2Bytes convert string to []byte
func String2Bytes(val string) []byte {
return []byte(val)
}

//convert string to int
// String2Int convert string to int
func String2Int(val string) (int, error) {
return strconv.Atoi(val)
}

//convert int to string
// Int2String convert int to string
func Int2String(val int) string {
return strconv.Itoa(val)
}

// String2Int64 convert string to int64
func String2Int64(val string) (int64, error) {
return strconv.ParseInt(val, 10, 64)
}

// Int642String convert int64 to string
func Int642String(val int64) string {
return strconv.FormatInt(val, 10)
}

// String2UInt64 convert string to uint64
func String2UInt64(val string) (uint64, error) {
return strconv.ParseUint(val, 10, 64)
}

// UInt642String convert uint64 to string
func UInt642String(val uint64) string{
return strconv.FormatUint(val, 10)
}

// NSToTime convert ns to time.Time
func NSToTime(ns int64) (time.Time, error) {
if ns <= 0 {
return time.Time{}, errors.New("ns is err")
Expand Down
56 changes: 52 additions & 4 deletions middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,34 @@ type RequestLogMiddleware struct {
}

func (m *RequestLogMiddleware) Handle(ctx Context) error {
var timeDuration time.Duration
var timeTaken uint64
var err error
m.Next(ctx)
timetaken := int64(time.Now().Sub(ctx.(*HttpContext).startTime) / time.Millisecond)
log := ctx.Request().Url() + " " + logContext(ctx, timetaken)
if ctx.Items().Exists(ItemKeyHandleDuration){
timeDuration, err = time.ParseDuration(ctx.Items().GetString(ItemKeyHandleDuration))
if err != nil{
timeTaken = 0
}else{
timeTaken = uint64(timeDuration/time.Millisecond)
}
}else{
var begin time.Time
beginVal, exists := ctx.Items().Get(ItemKeyHandleStartTime)
if !exists{
begin = time.Now()
}else{
begin = beginVal.(time.Time)
}
timeTaken = uint64(time.Now().Sub(begin) / time.Millisecond)
}
log := ctx.Request().Url() + " " + logContext(ctx, timeTaken)
logger.Logger().Debug(log, LogTarget_HttpRequest)
return nil
}

//get default log string
func logContext(ctx Context, timetaken int64) string {
func logContext(ctx Context, timetaken uint64) string {
var reqbytelen, resbytelen, method, proto, status, userip string
if ctx != nil {
reqbytelen = convert.Int642String(ctx.Request().ContentLength)
Expand All @@ -151,7 +170,36 @@ func logContext(ctx Context, timetaken int64) string {
log += status + " "
log += reqbytelen + " "
log += resbytelen + " "
log += convert.Int642String(timetaken)
log += convert.UInt642String(timetaken)

return log
}

// TimeoutHookMiddleware 超时钩子中间件
type TimeoutHookMiddleware struct {
BaseMiddlware
HookHandle StandardHandle
TimeoutDuration time.Duration
}

func (m *TimeoutHookMiddleware) Handle(ctx Context) error {
var begin time.Time
if m.HookHandle != nil{
beginVal, exists := ctx.Items().Get(ItemKeyHandleStartTime)
if !exists{
begin = time.Now()
}else{
begin = beginVal.(time.Time)
}
}
//Do next
m.Next(ctx)
if m.HookHandle != nil{
realDuration := time.Now().Sub(begin)
ctx.Items().Set(ItemKeyHandleDuration, realDuration)
if realDuration > m.TimeoutDuration{
m.HookHandle(ctx)
}
}
return nil
}
9 changes: 9 additions & 0 deletions vendor/gopkg.in/yaml.v2/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading