Support customized logger

This commit is contained in:
Andy Pan 2020-03-13 00:02:19 +08:00
parent ef20703b02
commit e507ae340f
7 changed files with 113 additions and 80 deletions

73
ants.go
View File

@ -24,7 +24,9 @@ package ants
import ( import (
"errors" "errors"
"log"
"math" "math"
"os"
"runtime" "runtime"
"time" "time"
) )
@ -81,75 +83,16 @@ var (
return 1 return 1
}() }()
defaultLogger = Logger(log.New(os.Stderr, "", log.LstdFlags))
// Init a instance pool when importing ants. // Init a instance pool when importing ants.
defaultAntsPool, _ = NewPool(DefaultAntsPoolSize) defaultAntsPool, _ = NewPool(DefaultAntsPoolSize)
) )
// Option represents the optional function. // Logger is used for logging formatted messages.
type Option func(opts *Options) type Logger interface {
// Printf must have the same semantics as log.Printf.
// Options contains all options which will be applied when instantiating a ants pool. Printf(format string, args ...interface{})
type Options struct {
// ExpiryDuration sets the expired time of every worker.
ExpiryDuration time.Duration
// PreAlloc indicates whether to make memory pre-allocation when initializing Pool.
PreAlloc bool
// Max number of goroutine blocking on pool.Submit.
// 0 (default value) means no such limit.
MaxBlockingTasks int
// When Nonblocking is true, Pool.Submit will never be blocked.
// ErrPoolOverload will be returned when Pool.Submit cannot be done at once.
// When Nonblocking is true, MaxBlockingTasks is inoperative.
Nonblocking bool
// PanicHandler is used to handle panics from each worker goroutine.
// if nil, panics will be thrown out again from worker goroutines.
PanicHandler func(interface{})
}
// WithOptions accepts the whole options config.
func WithOptions(options Options) Option {
return func(opts *Options) {
*opts = options
}
}
// WithExpiryDuration sets up the interval time of cleaning up goroutines.
func WithExpiryDuration(expiryDuration time.Duration) Option {
return func(opts *Options) {
opts.ExpiryDuration = expiryDuration
}
}
// WithPreAlloc indicates whether it should malloc for workers.
func WithPreAlloc(preAlloc bool) Option {
return func(opts *Options) {
opts.PreAlloc = preAlloc
}
}
// WithMaxBlockingTasks sets up the maximum number of goroutines that are blocked when it reaches the capacity of pool.
func WithMaxBlockingTasks(maxBlockingTasks int) Option {
return func(opts *Options) {
opts.MaxBlockingTasks = maxBlockingTasks
}
}
// WithNonblocking indicates that pool will return nil when there is no available workers.
func WithNonblocking(nonblocking bool) Option {
return func(opts *Options) {
opts.Nonblocking = nonblocking
}
}
// WithPanicHandler sets up panic handler.
func WithPanicHandler(panicHandler func(interface{})) Option {
return func(opts *Options) {
opts.PanicHandler = panicHandler
}
} }
// Submit submits a task to pool. // Submit submits a task to pool.

View File

@ -23,6 +23,8 @@
package ants package ants
import ( import (
"log"
"os"
"runtime" "runtime"
"sync" "sync"
"sync/atomic" "sync/atomic"
@ -546,7 +548,7 @@ func TestRestCodeCoverage(t *testing.T) {
poolOpts, _ := NewPool(1, WithOptions(options)) poolOpts, _ := NewPool(1, WithOptions(options))
t.Logf("Pool with options, capacity: %d", poolOpts.Cap()) t.Logf("Pool with options, capacity: %d", poolOpts.Cap())
p0, _ := NewPool(TestSize) p0, _ := NewPool(TestSize, WithLogger(log.New(os.Stderr, "", log.LstdFlags)))
defer func() { defer func() {
_ = p0.Submit(demoFunc) _ = p0.Submit(demoFunc)
}() }()

88
options.go Normal file
View File

@ -0,0 +1,88 @@
package ants
import "time"
// Option represents the optional function.
type Option func(opts *Options)
func loadOptions(options ...Option) *Options {
opts := new(Options)
for _, option := range options {
option(opts)
}
return opts
}
// Options contains all options which will be applied when instantiating a ants pool.
type Options struct {
// ExpiryDuration sets the expired time of every worker.
ExpiryDuration time.Duration
// PreAlloc indicates whether to make memory pre-allocation when initializing Pool.
PreAlloc bool
// Max number of goroutine blocking on pool.Submit.
// 0 (default value) means no such limit.
MaxBlockingTasks int
// When Nonblocking is true, Pool.Submit will never be blocked.
// ErrPoolOverload will be returned when Pool.Submit cannot be done at once.
// When Nonblocking is true, MaxBlockingTasks is inoperative.
Nonblocking bool
// PanicHandler is used to handle panics from each worker goroutine.
// if nil, panics will be thrown out again from worker goroutines.
PanicHandler func(interface{})
// Logger is the customized logger for logging info, if it is not set, default standard logger from log package is used.
Logger Logger
}
// WithOptions accepts the whole options config.
func WithOptions(options Options) Option {
return func(opts *Options) {
*opts = options
}
}
// WithExpiryDuration sets up the interval time of cleaning up goroutines.
func WithExpiryDuration(expiryDuration time.Duration) Option {
return func(opts *Options) {
opts.ExpiryDuration = expiryDuration
}
}
// WithPreAlloc indicates whether it should malloc for workers.
func WithPreAlloc(preAlloc bool) Option {
return func(opts *Options) {
opts.PreAlloc = preAlloc
}
}
// WithMaxBlockingTasks sets up the maximum number of goroutines that are blocked when it reaches the capacity of pool.
func WithMaxBlockingTasks(maxBlockingTasks int) Option {
return func(opts *Options) {
opts.MaxBlockingTasks = maxBlockingTasks
}
}
// WithNonblocking indicates that pool will return nil when there is no available workers.
func WithNonblocking(nonblocking bool) Option {
return func(opts *Options) {
opts.Nonblocking = nonblocking
}
}
// WithPanicHandler sets up panic handler.
func WithPanicHandler(panicHandler func(interface{})) Option {
return func(opts *Options) {
opts.PanicHandler = panicHandler
}
}
// WithLogger sets up a customized logger.
func WithLogger(logger Logger) Option {
return func(opts *Options) {
opts.Logger = logger
}
}

View File

@ -96,10 +96,7 @@ func NewPool(size int, options ...Option) (*Pool, error) {
return nil, ErrInvalidPoolSize return nil, ErrInvalidPoolSize
} }
opts := new(Options) opts := loadOptions(options...)
for _, option := range options {
option(opts)
}
if expiry := opts.ExpiryDuration; expiry < 0 { if expiry := opts.ExpiryDuration; expiry < 0 {
return nil, ErrInvalidPoolExpiry return nil, ErrInvalidPoolExpiry
@ -107,6 +104,10 @@ func NewPool(size int, options ...Option) (*Pool, error) {
opts.ExpiryDuration = DefaultCleanIntervalTime opts.ExpiryDuration = DefaultCleanIntervalTime
} }
if opts.Logger == nil {
opts.Logger = defaultLogger
}
p := &Pool{ p := &Pool{
capacity: int32(size), capacity: int32(size),
lock: internal.NewSpinLock(), lock: internal.NewSpinLock(),

View File

@ -117,10 +117,7 @@ func NewPoolWithFunc(size int, pf func(interface{}), options ...Option) (*PoolWi
return nil, ErrLackPoolFunc return nil, ErrLackPoolFunc
} }
opts := new(Options) opts := loadOptions(options...)
for _, option := range options {
option(opts)
}
if expiry := opts.ExpiryDuration; expiry < 0 { if expiry := opts.ExpiryDuration; expiry < 0 {
return nil, ErrInvalidPoolExpiry return nil, ErrInvalidPoolExpiry
@ -128,6 +125,10 @@ func NewPoolWithFunc(size int, pf func(interface{}), options ...Option) (*PoolWi
opts.ExpiryDuration = DefaultCleanIntervalTime opts.ExpiryDuration = DefaultCleanIntervalTime
} }
if opts.Logger == nil {
opts.Logger = defaultLogger
}
p := &PoolWithFunc{ p := &PoolWithFunc{
capacity: int32(size), capacity: int32(size),
poolFunc: pf, poolFunc: pf,

View File

@ -23,7 +23,6 @@
package ants package ants
import ( import (
"log"
"runtime" "runtime"
"time" "time"
) )
@ -54,10 +53,10 @@ func (w *goWorker) run() {
if ph := w.pool.options.PanicHandler; ph != nil { if ph := w.pool.options.PanicHandler; ph != nil {
ph(p) ph(p)
} else { } else {
log.Printf("worker exits from a panic: %v\n", p) w.pool.options.Logger.Printf("worker exits from a panic: %v\n", p)
var buf [4096]byte var buf [4096]byte
n := runtime.Stack(buf[:], false) n := runtime.Stack(buf[:], false)
log.Printf("worker exits from panic: %s\n", string(buf[:n])) w.pool.options.Logger.Printf("worker exits from panic: %s\n", string(buf[:n]))
} }
} }
}() }()

View File

@ -23,7 +23,6 @@
package ants package ants
import ( import (
"log"
"runtime" "runtime"
"time" "time"
) )
@ -54,10 +53,10 @@ func (w *goWorkerWithFunc) run() {
if ph := w.pool.options.PanicHandler; ph != nil { if ph := w.pool.options.PanicHandler; ph != nil {
ph(p) ph(p)
} else { } else {
log.Printf("worker with func exits from a panic: %v\n", p) w.pool.options.Logger.Printf("worker with func exits from a panic: %v\n", p)
var buf [4096]byte var buf [4096]byte
n := runtime.Stack(buf[:], false) n := runtime.Stack(buf[:], false)
log.Printf("worker with func exits from panic: %s\n", string(buf[:n])) w.pool.options.Logger.Printf("worker with func exits from panic: %s\n", string(buf[:n]))
} }
} }
}() }()