Skip to content

Commit

Permalink
1.5.0
Browse files Browse the repository at this point in the history
Signed-off-by: Kirill Danshin <k@guava.by>
  • Loading branch information
kirillDanshin committed Nov 6, 2018
1 parent 32bd735 commit bfe0390
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 13 deletions.
7 changes: 1 addition & 6 deletions app_listenAndServeAutoTLS.go
Expand Up @@ -70,12 +70,7 @@ func (app *App) ListenAndServeAutoTLS(addr string, cachePath ...string) error {
}

tlsConfig := getDefaultTLSConfig()
tlsConfig.GetCertificate = func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
var (
cert *tls.Certificate
err error
)

tlsConfig.GetCertificate = func(hello *tls.ClientHelloInfo) (cert *tls.Certificate, err error) {
if len(hello.ServerName) == 0 || hello.ServerName == localhost {
hello.ServerName = localhost
cert, err = selfSignedCertificate(hello)
Expand Down
8 changes: 6 additions & 2 deletions context_proxy.go
Expand Up @@ -14,9 +14,13 @@ import (
)

// Proxy request to given url
func (ctx *Context) Proxy(url string) error {
func (ctx *Context) Proxy(url string) (err error) {
proxyReq := fasthttp.AcquireRequest()
ctx.Request.CopyTo(proxyReq)
proxyReq.SetRequestURI(url)
return fasthttp.Do(proxyReq, &ctx.Response)

err = fasthttp.Do(proxyReq, &ctx.Response)

fasthttp.ReleaseRequest(proxyReq)
return
}
12 changes: 9 additions & 3 deletions docs/CHANGELOG.md
@@ -1,19 +1,25 @@
# Patch release: 1.5.0
- Separate store static route. Allows both `/post/:id` and `/post/about` routes
- Healtchecks module added
- Fix resource usage leak in ctx.Proxy()
- `Sub()` now allows to convert `App`'s root router to a SubRouter type

# Patch release: 1.4.2
- Setting of cookie path fixed

# Patch release: 1.4.1
- Regression fixed: empty app name. Now if no `OptAppName` provided `App.name` will be set to default
- Regression fixed: empty app name. Now if no `OptAppName` provided `App.name` will fallback to default setting

# Minor release: 1.4.0
- Added `OptAppName` option for App initializer
- Fixed ability to set empty `""` server name
- Fixed `fasthttp.Server` name set via `App.SetName()`
- Method `App.SetName()` market as deprecated in favor of `OptAppName`
- Methods `App.ListenAndServeAllDev()` & `App.ListenAndServeAutoTLSDev()` marked as deprecated and from now is simple aliases of `App.ListenAndServeAll()` & `App.ListenAndServeAutoTLS()` accordingly
- `App.ListenAndServeAllDev()` and `App.ListenAndServeAutoTLSDev()` methods marked as deprecated and from now is simple aliases of `App.ListenAndServeAll()` and `App.ListenAndServeAutoTLS()` accordingly
- Fixed `go.mod` dependencies and `go mod vendor` applied to support older versions of GO

# Patch release: 1.3.2
- Added `SubRouter.Handle()` method similar to `Router.Handle()` & `App.Handle()`.
- Added `SubRouter.Handle()` method with the same behaviour as `Router.Handle()` and `App.Handle()`.

# Patch release: 1.3.1
- Fix healthcheck formatting
Expand Down
23 changes: 23 additions & 0 deletions healthchecks/hc.go
@@ -0,0 +1,23 @@
package healthchecks

// Register both ping and healthcheck endpoints
func Register(r interface{}, collectors ...func() (statKey string, stats interface{})) error {
return doReg(r, collectors, true, true)
}

// RegisterPing registers ping endpoint
func RegisterPing(r interface{}) error {
return doReg(r, nil, true, false)
}

// RegisterHealthcheck registers healthcheck endpoint
func RegisterHealthcheck(r interface{}, collectors ...func() (statKey string, stats interface{})) error {
return doReg(r, collectors, false, true)
}

// ServeHealthcheck serves healthcheck
func ServeHealthcheck(collectors ...func() (statKey string, stats interface{})) func() interface{} {
return func() interface{} {
return check(collectors...)
}
}
136 changes: 136 additions & 0 deletions healthchecks/hc_internal.go
@@ -0,0 +1,136 @@
package healthchecks

import (
"errors"
"runtime"
"strings"

sigar "github.com/cloudfoundry/gosigar"
"github.com/gramework/gramework"
"github.com/gramework/gramework/internal/gfmt"
)

type routerable interface{}

type hc struct {
CPUClock string `json:"cpu_clock"`
RAM ramJSON `json:"ram_usage"`
Swap ramJSON `json:"swap_usage"`

LA laJSON `json:"load_average"`
LoadStatus string `json:"load_alert_status"`

Uptime string `json:"uptime"`

Custom map[string]interface{} `json:"custom_metrics,omitempty"`
}

type laJSON struct {
One float64 `json:"one"`
Five float64 `json:"five"`
Fifteen float64 `json:"fifteen"`
}

type ramJSON struct {
Used string `json:"used"`
Total string `json:"total"`
}

type sigarWrapper struct {
sigar.ConcreteSigar
}

func (s sigarWrapper) swap() ramJSON {
swap, err := s.GetSwap()
if err != nil {
swap.Get()
}
return ramJSON{
Used: gfmt.Si(swap.Used),
Total: gfmt.Si(swap.Total),
}
}
func (s sigarWrapper) ram() ramJSON {
mem, err := s.GetMem()
if err != nil {
mem.Get()
}
return ramJSON{
Used: gfmt.Si(mem.Used),
Total: gfmt.Si(mem.Total),
}
}

func doReg(r interface{}, collectors []func() (statKey string, stats interface{}), registerPing, registerHC bool) error {
app, isApp := r.(*gramework.App)
sr, isSr := r.(*gramework.SubRouter)
if !isApp && !isSr {
return errors.New("unsupported handler type")
}

if isApp {
sr = app.Sub("")
}

if registerPing {
sr.GET("/ping", "pong")
}
if registerHC {
sr.GET("/healthcheck", ServeHealthcheck(collectors...))
}

return nil
}

func check(collectors ...func() (statKey string, stats interface{})) interface{} {
s := sigarWrapper{sigar.ConcreteSigar{}}
currentCheck := &hc{
CPUClock: gfmt.Si(uint64(gramework.TicksPerSecond())),
RAM: s.ram(),
Swap: s.swap(),
LoadStatus: "<unknown>",
}
la, err := s.GetLoadAverage()
if err != nil {
err = la.Get() // retry
}

if err == nil {
maxLA := float64(runtime.NumCPU() + 2)
currentCheck.LA = laJSON(la)
diffOne := maxLA - la.One
diffFive := maxLA - la.Five
diffFifteen := maxLA - la.Fifteen

alertTrigger := float64(-3)
warnTrigger := float64(0)

if diffOne < alertTrigger || diffFive < alertTrigger || diffFifteen < alertTrigger {
currentCheck.LoadStatus = "alert"
} else if diffOne < warnTrigger || diffFive < warnTrigger || diffFifteen < warnTrigger {
currentCheck.LoadStatus = "warn"
} else {
currentCheck.LoadStatus = "ok"
}
}

uptime := sigar.Uptime{}
err = uptime.Get()
if err != nil {
err = uptime.Get() // retry
}
if err == nil {
currentCheck.Uptime = strings.TrimSpace(uptime.Format())
}

if len(collectors) > 0 {
currentCheck.Custom = make(map[string]interface{})
}
for _, cb := range collectors {
if cb != nil {
key, stats := cb()
currentCheck.Custom[key] = stats
}
}
return currentCheck
}
41 changes: 41 additions & 0 deletions internal/gfmt/si.go
@@ -0,0 +1,41 @@
package gfmt

import "fmt"

// Si formats a number in a short si format
func Si(n uint64) string {
suff := siRaw
x := float64(n)
for ; x >= 1024; x = x / 1024 {
suff++
}

return fmt.Sprintf("%.2f%s", x, suff.String())
}

type siSuff uint

const (
siRaw siSuff = iota
siKilo
siMega
siGiga
siTera
)

func (s siSuff) String() string {
switch s {
case siRaw:
return ""
case siKilo:
return "K"
case siMega:
return "M"
case siGiga:
return "G"
case siTera:
return "T"
default:
return "T"
}
}
2 changes: 1 addition & 1 deletion subroute.go
Expand Up @@ -136,7 +136,7 @@ func (r *SubRouter) Sub(path string) *SubRouter {
}

func (r *SubRouter) prefixedRoute(route string) string {
if r.prefix[len(r.prefix)-1] != '/' && route[0] != '/' {
if len(r.prefix) > 0 && r.prefix[len(r.prefix)-1] != '/' && route[0] != '/' {
return fmt.Sprintf("%s/%s", r.prefix, route)
}

Expand Down
2 changes: 1 addition & 1 deletion version.go
Expand Up @@ -11,6 +11,6 @@ package gramework

// Version gives you the gramework version you use now
const (
Version = "1.4.2"
Version = "1.5.0"
DefaultAppName = "gramework/" + Version
)

0 comments on commit bfe0390

Please sign in to comment.