mirror of
https://github.com/astaxie/beego.git
synced 2025-06-14 19:10:40 +00:00
remove pkg directory;
remove build directory; remove githook directory;
This commit is contained in:
87
core/governor/command.go
Normal file
87
core/governor/command.go
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright 2020
|
||||
//
|
||||
// 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 governor
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Command is an experimental interface
|
||||
// We try to use this to decouple modules
|
||||
// All other modules depends on this, and they register the command they support
|
||||
// We may change the API in the future, so be careful about this.
|
||||
type Command interface {
|
||||
Execute(params ...interface{}) *Result
|
||||
}
|
||||
|
||||
var CommandNotFound = errors.New("Command not found")
|
||||
|
||||
type Result struct {
|
||||
// Status is the same as http.Status
|
||||
Status int
|
||||
Error error
|
||||
Content interface{}
|
||||
}
|
||||
|
||||
func (r *Result) IsSuccess() bool {
|
||||
return r.Status >= 200 && r.Status < 300
|
||||
}
|
||||
|
||||
// CommandRegistry stores all commands
|
||||
// name => command
|
||||
type moduleCommands map[string]Command
|
||||
|
||||
// Get returns command with the name
|
||||
func (m moduleCommands) Get(name string) Command {
|
||||
c, ok := m[name]
|
||||
if ok {
|
||||
return c
|
||||
}
|
||||
return &doNothingCommand{}
|
||||
}
|
||||
|
||||
// module name => moduleCommand
|
||||
type commandRegistry map[string]moduleCommands
|
||||
|
||||
// Get returns module's commands
|
||||
func (c commandRegistry) Get(moduleName string) moduleCommands {
|
||||
if mcs, ok := c[moduleName]; ok {
|
||||
return mcs
|
||||
}
|
||||
res := make(moduleCommands)
|
||||
c[moduleName] = res
|
||||
return res
|
||||
}
|
||||
|
||||
var cmdRegistry = make(commandRegistry)
|
||||
|
||||
// RegisterCommand is not thread-safe
|
||||
// do not use it in concurrent case
|
||||
func RegisterCommand(module string, commandName string, command Command) {
|
||||
cmdRegistry.Get(module)[commandName] = command
|
||||
}
|
||||
|
||||
func GetCommand(module string, cmdName string) Command {
|
||||
return cmdRegistry.Get(module).Get(cmdName)
|
||||
}
|
||||
|
||||
type doNothingCommand struct{}
|
||||
|
||||
func (d *doNothingCommand) Execute(params ...interface{}) *Result {
|
||||
return &Result{
|
||||
Status: 404,
|
||||
Error: CommandNotFound,
|
||||
}
|
||||
}
|
48
core/governor/healthcheck.go
Normal file
48
core/governor/healthcheck.go
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2014 beego Author. All Rights Reserved.
|
||||
//
|
||||
// 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 governor healthcheck
|
||||
//
|
||||
// type DatabaseCheck struct {
|
||||
// }
|
||||
//
|
||||
// func (dc *DatabaseCheck) Check() error {
|
||||
// if dc.isConnected() {
|
||||
// return nil
|
||||
// } else {
|
||||
// return errors.New("can't connect database")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// AddHealthCheck("database",&DatabaseCheck{})
|
||||
//
|
||||
// more docs: http://beego.me/docs/module/toolbox.md
|
||||
package governor
|
||||
|
||||
// AdminCheckList holds health checker map
|
||||
var AdminCheckList map[string]HealthChecker
|
||||
|
||||
// HealthChecker health checker interface
|
||||
type HealthChecker interface {
|
||||
Check() error
|
||||
}
|
||||
|
||||
// AddHealthCheck add health checker with name string
|
||||
func AddHealthCheck(name string, hc HealthChecker) {
|
||||
AdminCheckList[name] = hc
|
||||
}
|
||||
|
||||
func init() {
|
||||
AdminCheckList = make(map[string]HealthChecker)
|
||||
}
|
158
core/governor/profile.go
Normal file
158
core/governor/profile.go
Normal file
@ -0,0 +1,158 @@
|
||||
// Copyright 2014 beego Author. All Rights Reserved.
|
||||
//
|
||||
// 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 governor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"runtime/pprof"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego/core/utils"
|
||||
)
|
||||
|
||||
var startTime = time.Now()
|
||||
var pid int
|
||||
|
||||
func init() {
|
||||
pid = os.Getpid()
|
||||
}
|
||||
|
||||
// ProcessInput parse input command string
|
||||
func ProcessInput(input string, w io.Writer) {
|
||||
switch input {
|
||||
case "lookup goroutine":
|
||||
p := pprof.Lookup("goroutine")
|
||||
p.WriteTo(w, 2)
|
||||
case "lookup heap":
|
||||
p := pprof.Lookup("heap")
|
||||
p.WriteTo(w, 2)
|
||||
case "lookup threadcreate":
|
||||
p := pprof.Lookup("threadcreate")
|
||||
p.WriteTo(w, 2)
|
||||
case "lookup block":
|
||||
p := pprof.Lookup("block")
|
||||
p.WriteTo(w, 2)
|
||||
case "get cpuprof":
|
||||
GetCPUProfile(w)
|
||||
case "get memprof":
|
||||
MemProf(w)
|
||||
case "gc summary":
|
||||
PrintGCSummary(w)
|
||||
}
|
||||
}
|
||||
|
||||
// MemProf record memory profile in pprof
|
||||
func MemProf(w io.Writer) {
|
||||
filename := "mem-" + strconv.Itoa(pid) + ".memprof"
|
||||
if f, err := os.Create(filename); err != nil {
|
||||
fmt.Fprintf(w, "create file %s error %s\n", filename, err.Error())
|
||||
log.Fatal("record heap profile failed: ", err)
|
||||
} else {
|
||||
runtime.GC()
|
||||
pprof.WriteHeapProfile(f)
|
||||
f.Close()
|
||||
fmt.Fprintf(w, "create heap profile %s \n", filename)
|
||||
_, fl := path.Split(os.Args[0])
|
||||
fmt.Fprintf(w, "Now you can use this to check it: go tool pprof %s %s\n", fl, filename)
|
||||
}
|
||||
}
|
||||
|
||||
// GetCPUProfile start cpu profile monitor
|
||||
func GetCPUProfile(w io.Writer) {
|
||||
sec := 30
|
||||
filename := "cpu-" + strconv.Itoa(pid) + ".pprof"
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
|
||||
log.Fatal("record cpu profile failed: ", err)
|
||||
}
|
||||
pprof.StartCPUProfile(f)
|
||||
time.Sleep(time.Duration(sec) * time.Second)
|
||||
pprof.StopCPUProfile()
|
||||
|
||||
fmt.Fprintf(w, "create cpu profile %s \n", filename)
|
||||
_, fl := path.Split(os.Args[0])
|
||||
fmt.Fprintf(w, "Now you can use this to check it: go tool pprof %s %s\n", fl, filename)
|
||||
}
|
||||
|
||||
// PrintGCSummary print gc information to io.Writer
|
||||
func PrintGCSummary(w io.Writer) {
|
||||
memStats := &runtime.MemStats{}
|
||||
runtime.ReadMemStats(memStats)
|
||||
gcstats := &debug.GCStats{PauseQuantiles: make([]time.Duration, 100)}
|
||||
debug.ReadGCStats(gcstats)
|
||||
|
||||
printGC(memStats, gcstats, w)
|
||||
}
|
||||
|
||||
func printGC(memStats *runtime.MemStats, gcstats *debug.GCStats, w io.Writer) {
|
||||
|
||||
if gcstats.NumGC > 0 {
|
||||
lastPause := gcstats.Pause[0]
|
||||
elapsed := time.Now().Sub(startTime)
|
||||
overhead := float64(gcstats.PauseTotal) / float64(elapsed) * 100
|
||||
allocatedRate := float64(memStats.TotalAlloc) / elapsed.Seconds()
|
||||
|
||||
fmt.Fprintf(w, "NumGC:%d Pause:%s Pause(Avg):%s Overhead:%3.2f%% Alloc:%s Sys:%s Alloc(Rate):%s/s Histogram:%s %s %s \n",
|
||||
gcstats.NumGC,
|
||||
utils.ToShortTimeFormat(lastPause),
|
||||
utils.ToShortTimeFormat(avg(gcstats.Pause)),
|
||||
overhead,
|
||||
toH(memStats.Alloc),
|
||||
toH(memStats.Sys),
|
||||
toH(uint64(allocatedRate)),
|
||||
utils.ToShortTimeFormat(gcstats.PauseQuantiles[94]),
|
||||
utils.ToShortTimeFormat(gcstats.PauseQuantiles[98]),
|
||||
utils.ToShortTimeFormat(gcstats.PauseQuantiles[99]))
|
||||
} else {
|
||||
// while GC has disabled
|
||||
elapsed := time.Now().Sub(startTime)
|
||||
allocatedRate := float64(memStats.TotalAlloc) / elapsed.Seconds()
|
||||
|
||||
fmt.Fprintf(w, "Alloc:%s Sys:%s Alloc(Rate):%s/s\n",
|
||||
toH(memStats.Alloc),
|
||||
toH(memStats.Sys),
|
||||
toH(uint64(allocatedRate)))
|
||||
}
|
||||
}
|
||||
|
||||
func avg(items []time.Duration) time.Duration {
|
||||
var sum time.Duration
|
||||
for _, item := range items {
|
||||
sum += item
|
||||
}
|
||||
return time.Duration(int64(sum) / int64(len(items)))
|
||||
}
|
||||
|
||||
// format bytes number friendly
|
||||
func toH(bytes uint64) string {
|
||||
switch {
|
||||
case bytes < 1024:
|
||||
return fmt.Sprintf("%dB", bytes)
|
||||
case bytes < 1024*1024:
|
||||
return fmt.Sprintf("%.2fK", float64(bytes)/1024)
|
||||
case bytes < 1024*1024*1024:
|
||||
return fmt.Sprintf("%.2fM", float64(bytes)/1024/1024)
|
||||
default:
|
||||
return fmt.Sprintf("%.2fG", float64(bytes)/1024/1024/1024)
|
||||
}
|
||||
}
|
28
core/governor/profile_test.go
Normal file
28
core/governor/profile_test.go
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2014 beego Author. All Rights Reserved.
|
||||
//
|
||||
// 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 governor
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestProcessInput(t *testing.T) {
|
||||
ProcessInput("lookup goroutine", os.Stdout)
|
||||
ProcessInput("lookup heap", os.Stdout)
|
||||
ProcessInput("lookup threadcreate", os.Stdout)
|
||||
ProcessInput("lookup block", os.Stdout)
|
||||
ProcessInput("gc summary", os.Stdout)
|
||||
}
|
Reference in New Issue
Block a user