func Interval() time.Duration {
	i, err := strconv.ParseFloat(os.Getenv("COLLECTD_INTERVAL"), 64)
	if err != nil {
		log.Printf("unable to determine default interval: %v", err)
		return time.Second * 10
	}
	return time.Duration(i * float64(time.Second))
}
Interval determines the default interval from the "COLLECTD_INTERVAL"
environment variable. It falls back to 10s if the environment variable is
unset or cannot be parsed.
package exec  
import (
	"context"
	"log"
	"os"
	"strconv"
	"sync"
	"time"
	"collectd.org/api"
	"collectd.org/format"
)
var Putval api.Writer = format.NewPutval(os.Stdout)
type callback interface {
	run(context.Context, *sync.WaitGroup)
	stop()
}
type Executor struct {
	cb    []callback
	group sync.WaitGroup
}
func NewExecutor() *Executor {
	return &Executor{
		group: sync.WaitGroup{},
	}
}
func (e *Executor) ValueCallback(callback func() api.Value, vl *api.ValueList) {
	e.cb = append(e.cb, &valueCallback{
		callback: callback,
		vl:       *vl,
		done:     make(chan struct{}),
	})
}
func (e *Executor) VoidCallback(callback func(context.Context, time.Duration), interval time.Duration) {
	e.cb = append(e.cb, voidCallback{
		callback: callback,
		interval: interval,
		done:     make(chan struct{}),
	})
}
func (e *Executor) Run(ctx context.Context) {
	for _, cb := range e.cb {
		e.group.Add(1)
		go cb.run(ctx, &e.group)
	}
	e.group.Wait()
}
func (e *Executor) Stop() {
	for _, cb := range e.cb {
		cb.stop()
	}
}
type valueCallback struct {
	callback func() api.Value
	vl       api.ValueList
	done     chan struct{}
}
func (cb *valueCallback) run(ctx context.Context, g *sync.WaitGroup) {
	defer g.Done()
	if cb.vl.Host == "" {
		cb.vl.Host = Hostname()
	}
	cb.vl.Interval = sanitizeInterval(cb.vl.Interval)
	ticker := time.NewTicker(cb.vl.Interval)
	for {
		select {
		case <-ticker.C:
			cb.vl.Values = []api.Value{cb.callback()}
			cb.vl.Time = time.Now()
			Putval.Write(ctx, &cb.vl)
		case <-cb.done:
			return
		case <-ctx.Done():
			return
		}
	}
}
func (cb *valueCallback) stop() {
	close(cb.done)
}
type voidCallback struct {
	callback func(context.Context, time.Duration)
	interval time.Duration
	done     chan struct{}
}
func (cb voidCallback) run(ctx context.Context, g *sync.WaitGroup) {
	defer g.Done()
	ticker := time.NewTicker(sanitizeInterval(cb.interval))
	for {
		select {
		case <-ticker.C:
			cb.callback(ctx, cb.interval)
		case <-cb.done:
			return
		case <-ctx.Done():
			return
		}
	}
}
func (cb voidCallback) stop() {
	close(cb.done)
}