add debug/profile package (#920)
* add debug/profile package * set service+version for profile
This commit is contained in:
		| @@ -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 | ||||||
| 	} | 	} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user