func (lgr *Logr) Flush() error {
	ctx, cancel := context.WithTimeout(context.Background(), lgr.options.flushTimeout)
	defer cancel()
	return lgr.FlushWithTimeout(ctx)
}
Flush blocks while flushing the logr queue and all target queues, by
writing existing log records to valid targets.
Any attempts to add new log records will block until flush is complete.
`logr.FlushTimeout` determines how long flush can execute before
timing out. Use `IsTimeoutError` to determine if the returned error is
due to a timeout.
package logr
import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"os"
	"sync"
	"sync/atomic"
	"time"
	"github.com/wiggin77/merror"
)
type Logr struct {
	tmux        sync.RWMutex  
	targetHosts []*TargetHost
	in         chan *LogRec
	quit       chan struct{}  
	done       chan struct{}  
	lvlCache   levelCache
	bufferPool sync.Pool
	options    *options
	metricsMux sync.RWMutex
	metrics    *metrics
	shutdown int32
}
func New(opts ...Option) (*Logr, error) {
	options := &options{
		maxQueueSize:    DefaultMaxQueueSize,
		enqueueTimeout:  DefaultEnqueueTimeout,
		shutdownTimeout: DefaultShutdownTimeout,
		flushTimeout:    DefaultFlushTimeout,
		maxPooledBuffer: DefaultMaxPooledBuffer,
	}
	lgr := &Logr{options: options}
	for _, opt := range opts {
		if err := opt(lgr); err != nil {
			return nil, err
		}
	}
	pkgName := GetLogrPackageName()
	if pkgName != "" {
		opt := StackFilter(pkgName, pkgName+"/targets", pkgName+"/formatters")
		_ = opt(lgr)
	}
	lgr.in = make(chan *LogRec, lgr.options.maxQueueSize)
	lgr.quit = make(chan struct{})
	lgr.done = make(chan struct{})
	if lgr.options.useSyncMapLevelCache {
		lgr.lvlCache = &syncMapLevelCache{}
	} else {
		lgr.lvlCache = &arrayLevelCache{}
	}
	lgr.lvlCache.setup()
	lgr.bufferPool = sync.Pool{
		New: func() interface{} {
			return new(bytes.Buffer)
		},
	}
	lgr.initMetrics(lgr.options.metricsCollector, lgr.options.metricsUpdateFreqMillis)
	go lgr.start()
	return lgr, nil
}
func (lgr *Logr) AddTarget(target Target, name string, filter Filter, formatter Formatter, maxQueueSize int) error {
	if lgr.IsShutdown() {
		return fmt.Errorf("AddTarget called after Logr shut down")
	}
	lgr.metricsMux.RLock()
	metrics := lgr.metrics
	lgr.metricsMux.RUnlock()
	hostOpts := targetHostOptions{
		name:         name,
		filter:       filter,
		formatter:    formatter,
		maxQueueSize: maxQueueSize,
		metrics:      metrics,
	}
	host, err := newTargetHost(target, hostOpts)
	if err != nil {
		return err
	}
	lgr.tmux.Lock()
	defer lgr.tmux.Unlock()
	lgr.targetHosts = append(lgr.targetHosts, host)
	lgr.ResetLevelCache()
	return nil
}
func (lgr *Logr) NewLogger() Logger {
	logger := Logger{lgr: lgr}
	return logger
}
var levelStatusDisabled = LevelStatus{}
func (lgr *Logr) IsLevelEnabled(lvl Level) LevelStatus {
	if atomic.LoadInt32(&lgr.shutdown) != 0 {
		return levelStatusDisabled
	}
	status, ok := lgr.lvlCache.get(lvl.ID)
	if ok {
		return status
	}
	status = LevelStatus{}
	lgr.tmux.RLock()
	defer lgr.tmux.RUnlock()
	for _, host := range lgr.targetHosts {
		enabled, level := host.IsLevelEnabled(lvl)
		if enabled {
			status.Enabled = true
			if level.Stacktrace || host.formatter.IsStacktraceNeeded() {
				status.Stacktrace = true
				break  
			}
		}
	}
	if err := lgr.lvlCache.put(lvl.ID, status); err != nil {
		lgr.ReportError(err)
		return LevelStatus{}
	}
	return status
}
func (lgr *Logr) HasTargets() bool {
	lgr.tmux.RLock()
	defer lgr.tmux.RUnlock()
	return len(lgr.targetHosts) > 0
}
type TargetInfo struct {
	Name string
	Type string
}
func (lgr *Logr) TargetInfos() []TargetInfo {
	infos := make([]TargetInfo, 0)
	lgr.tmux.RLock()
	defer lgr.tmux.RUnlock()
	for _, host := range lgr.targetHosts {
		inf := TargetInfo{
			Name: host.String(),
			Type: fmt.Sprintf("%T", host.target),
		}
		infos = append(infos, inf)
	}
	return infos
}
func (lgr *Logr) RemoveTargets(cxt context.Context, f func(ti TargetInfo) bool) error {
	errs := merror.New()
	hosts := make([]*TargetHost, 0)
	lgr.tmux.Lock()
	defer lgr.tmux.Unlock()
	for _, host := range lgr.targetHosts {
		inf := TargetInfo{
			Name: host.String(),
			Type: fmt.Sprintf("%T", host.target),
		}
		if f(inf) {
			if err := host.Shutdown(cxt); err != nil {
				errs.Append(err)
			}
		} else {
			hosts = append(hosts, host)
		}
	}
	lgr.targetHosts = hosts
	lgr.ResetLevelCache()
	return errs.ErrorOrNil()
}
func (lgr *Logr) ResetLevelCache() {
	lgr.lvlCache.clear()
}
func (lgr *Logr) SetMetricsCollector(collector MetricsCollector, updateFreqMillis int64) {
	lgr.initMetrics(collector, updateFreqMillis)
}
func (lgr *Logr) enqueue(rec *LogRec) {
	select {
	case lgr.in <- rec:
	default:
		if lgr.options.onQueueFull != nil && lgr.options.onQueueFull(rec, cap(lgr.in)) {
			return  
		}
		select {
		case <-time.After(lgr.options.enqueueTimeout):
			lgr.ReportError(fmt.Errorf("enqueue timed out for log rec [%v]", rec))
		case lgr.in <- rec:  
		}
	}
}