diff --git a/ants.go b/ants.go index de24d49..2df74ad 100644 --- a/ants.go +++ b/ants.go @@ -24,7 +24,9 @@ package ants import ( "errors" + "log" "math" + "os" "runtime" "time" ) @@ -81,75 +83,16 @@ var ( return 1 }() + defaultLogger = Logger(log.New(os.Stderr, "", log.LstdFlags)) + // Init a instance pool when importing ants. defaultAntsPool, _ = NewPool(DefaultAntsPoolSize) ) -// Option represents the optional function. -type Option func(opts *Options) - -// 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{}) -} - -// 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 - } +// Logger is used for logging formatted messages. +type Logger interface { + // Printf must have the same semantics as log.Printf. + Printf(format string, args ...interface{}) } // Submit submits a task to pool. diff --git a/ants_test.go b/ants_test.go index f424a0c..b1b977b 100644 --- a/ants_test.go +++ b/ants_test.go @@ -23,6 +23,8 @@ package ants import ( + "log" + "os" "runtime" "sync" "sync/atomic" @@ -546,7 +548,7 @@ func TestRestCodeCoverage(t *testing.T) { poolOpts, _ := NewPool(1, WithOptions(options)) t.Logf("Pool with options, capacity: %d", poolOpts.Cap()) - p0, _ := NewPool(TestSize) + p0, _ := NewPool(TestSize, WithLogger(log.New(os.Stderr, "", log.LstdFlags))) defer func() { _ = p0.Submit(demoFunc) }() diff --git a/options.go b/options.go new file mode 100644 index 0000000..709c63c --- /dev/null +++ b/options.go @@ -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 + } +} diff --git a/pool.go b/pool.go index 4044859..02dbdce 100644 --- a/pool.go +++ b/pool.go @@ -96,10 +96,7 @@ func NewPool(size int, options ...Option) (*Pool, error) { return nil, ErrInvalidPoolSize } - opts := new(Options) - for _, option := range options { - option(opts) - } + opts := loadOptions(options...) if expiry := opts.ExpiryDuration; expiry < 0 { return nil, ErrInvalidPoolExpiry @@ -107,6 +104,10 @@ func NewPool(size int, options ...Option) (*Pool, error) { opts.ExpiryDuration = DefaultCleanIntervalTime } + if opts.Logger == nil { + opts.Logger = defaultLogger + } + p := &Pool{ capacity: int32(size), lock: internal.NewSpinLock(), diff --git a/pool_func.go b/pool_func.go index 96a26ea..cd556dc 100644 --- a/pool_func.go +++ b/pool_func.go @@ -117,10 +117,7 @@ func NewPoolWithFunc(size int, pf func(interface{}), options ...Option) (*PoolWi return nil, ErrLackPoolFunc } - opts := new(Options) - for _, option := range options { - option(opts) - } + opts := loadOptions(options...) if expiry := opts.ExpiryDuration; expiry < 0 { return nil, ErrInvalidPoolExpiry @@ -128,6 +125,10 @@ func NewPoolWithFunc(size int, pf func(interface{}), options ...Option) (*PoolWi opts.ExpiryDuration = DefaultCleanIntervalTime } + if opts.Logger == nil { + opts.Logger = defaultLogger + } + p := &PoolWithFunc{ capacity: int32(size), poolFunc: pf, diff --git a/worker.go b/worker.go index 1b1f817..1a52d65 100644 --- a/worker.go +++ b/worker.go @@ -23,7 +23,6 @@ package ants import ( - "log" "runtime" "time" ) @@ -54,10 +53,10 @@ func (w *goWorker) run() { if ph := w.pool.options.PanicHandler; ph != nil { ph(p) } 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 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])) } } }() diff --git a/worker_func.go b/worker_func.go index 3f46d72..14a63c2 100644 --- a/worker_func.go +++ b/worker_func.go @@ -23,7 +23,6 @@ package ants import ( - "log" "runtime" "time" ) @@ -54,10 +53,10 @@ func (w *goWorkerWithFunc) run() { if ph := w.pool.options.PanicHandler; ph != nil { ph(p) } 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 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])) } } }()