add debug/profile package (#920)
* add debug/profile package * set service+version for profile
This commit is contained in:
parent
254045e9f3
commit
ce080d76c6
@ -71,12 +71,6 @@ var (
|
|||||||
DefaultCmd = newCmd()
|
DefaultCmd = newCmd()
|
||||||
|
|
||||||
DefaultFlags = []cli.Flag{
|
DefaultFlags = []cli.Flag{
|
||||||
cli.StringFlag{
|
|
||||||
Name: "runtime",
|
|
||||||
Usage: "Micro runtime",
|
|
||||||
EnvVar: "MICRO_RUNTIME",
|
|
||||||
Value: "local",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "client",
|
Name: "client",
|
||||||
EnvVar: "MICRO_CLIENT",
|
EnvVar: "MICRO_CLIENT",
|
||||||
@ -161,6 +155,11 @@ var (
|
|||||||
EnvVar: "MICRO_BROKER_ADDRESS",
|
EnvVar: "MICRO_BROKER_ADDRESS",
|
||||||
Usage: "Comma-separated list of broker addresses",
|
Usage: "Comma-separated list of broker addresses",
|
||||||
},
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "profile",
|
||||||
|
Usage: "Debug profiler for cpu and memory stats",
|
||||||
|
EnvVar: "MICRO_DEBUG_PROFILE",
|
||||||
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "registry",
|
Name: "registry",
|
||||||
EnvVar: "MICRO_REGISTRY",
|
EnvVar: "MICRO_REGISTRY",
|
||||||
@ -171,6 +170,12 @@ var (
|
|||||||
EnvVar: "MICRO_REGISTRY_ADDRESS",
|
EnvVar: "MICRO_REGISTRY_ADDRESS",
|
||||||
Usage: "Comma-separated list of registry addresses",
|
Usage: "Comma-separated list of registry addresses",
|
||||||
},
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "runtime",
|
||||||
|
Usage: "Runtime for building and running services e.g local, kubernetes",
|
||||||
|
EnvVar: "MICRO_RUNTIME",
|
||||||
|
Value: "local",
|
||||||
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "selector",
|
Name: "selector",
|
||||||
EnvVar: "MICRO_SELECTOR",
|
EnvVar: "MICRO_SELECTOR",
|
||||||
|
118
debug/profile/pprof/pprof.go
Normal file
118
debug/profile/pprof/pprof.go
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// Package pprof provides a pprof profiler
|
||||||
|
package pprof
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"runtime/pprof"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/debug/profile"
|
||||||
|
)
|
||||||
|
|
||||||
|
type profiler struct {
|
||||||
|
opts profile.Options
|
||||||
|
|
||||||
|
sync.Mutex
|
||||||
|
running bool
|
||||||
|
exit chan bool
|
||||||
|
|
||||||
|
// where the cpu profile is written
|
||||||
|
cpuFile *os.File
|
||||||
|
// where the mem profile is written
|
||||||
|
memFile *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *profiler) writeHeap(f *os.File) {
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
t := time.NewTicker(time.Second * 30)
|
||||||
|
defer t.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-t.C:
|
||||||
|
runtime.GC()
|
||||||
|
pprof.WriteHeapProfile(f)
|
||||||
|
case <-p.exit:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *profiler) Start() error {
|
||||||
|
p.Lock()
|
||||||
|
defer p.Unlock()
|
||||||
|
|
||||||
|
if p.running {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// create exit channel
|
||||||
|
p.exit = make(chan bool)
|
||||||
|
|
||||||
|
cpuFile := filepath.Join("/tmp", "cpu.pprof")
|
||||||
|
memFile := filepath.Join("/tmp", "mem.pprof")
|
||||||
|
|
||||||
|
if len(p.opts.Name) > 0 {
|
||||||
|
cpuFile = filepath.Join("/tmp", p.opts.Name+".cpu.pprof")
|
||||||
|
memFile = filepath.Join("/tmp", p.opts.Name+".mem.pprof")
|
||||||
|
}
|
||||||
|
|
||||||
|
f1, err := os.Create(cpuFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f2, err := os.Create(memFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// start cpu profiling
|
||||||
|
if err := pprof.StartCPUProfile(f1); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the heap periodically
|
||||||
|
go p.writeHeap(f2)
|
||||||
|
|
||||||
|
// set cpu file
|
||||||
|
p.cpuFile = f1
|
||||||
|
// set mem file
|
||||||
|
p.memFile = f2
|
||||||
|
|
||||||
|
p.running = true
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *profiler) Stop() error {
|
||||||
|
p.Lock()
|
||||||
|
defer p.Unlock()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-p.exit:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
close(p.exit)
|
||||||
|
pprof.StopCPUProfile()
|
||||||
|
p.cpuFile.Close()
|
||||||
|
p.running = false
|
||||||
|
p.cpuFile = nil
|
||||||
|
p.memFile = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProfile(opts ...profile.Option) profile.Profile {
|
||||||
|
var options profile.Options
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&options)
|
||||||
|
}
|
||||||
|
p := new(profiler)
|
||||||
|
p.opts = options
|
||||||
|
return p
|
||||||
|
}
|
23
debug/profile/profile.go
Normal file
23
debug/profile/profile.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Package profile is for profilers
|
||||||
|
package profile
|
||||||
|
|
||||||
|
type Profile interface {
|
||||||
|
// Start the profiler
|
||||||
|
Start() error
|
||||||
|
// Stop the profiler
|
||||||
|
Stop() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
// Name to use for the profile
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(o *Options)
|
||||||
|
|
||||||
|
// Name of the profile
|
||||||
|
func Name(n string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Name = n
|
||||||
|
}
|
||||||
|
}
|
16
service.go
16
service.go
@ -10,6 +10,8 @@ import (
|
|||||||
"github.com/micro/go-micro/client"
|
"github.com/micro/go-micro/client"
|
||||||
"github.com/micro/go-micro/config/cmd"
|
"github.com/micro/go-micro/config/cmd"
|
||||||
"github.com/micro/go-micro/debug/handler"
|
"github.com/micro/go-micro/debug/handler"
|
||||||
|
"github.com/micro/go-micro/debug/profile"
|
||||||
|
"github.com/micro/go-micro/debug/profile/pprof"
|
||||||
"github.com/micro/go-micro/metadata"
|
"github.com/micro/go-micro/metadata"
|
||||||
"github.com/micro/go-micro/plugin"
|
"github.com/micro/go-micro/plugin"
|
||||||
"github.com/micro/go-micro/server"
|
"github.com/micro/go-micro/server"
|
||||||
@ -147,6 +149,20 @@ func (s *service) Run() error {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// start the profiler
|
||||||
|
// TODO: set as an option to the service, don't just use pprof
|
||||||
|
if prof := os.Getenv("MICRO_DEBUG_PROFILE"); len(prof) > 0 {
|
||||||
|
service := s.opts.Server.Options().Name
|
||||||
|
version := s.opts.Server.Options().Version
|
||||||
|
profiler := pprof.NewProfile(
|
||||||
|
profile.Name(service + "." + version),
|
||||||
|
)
|
||||||
|
if err := profiler.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer profiler.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.Start(); err != nil {
|
if err := s.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user