func (fb *Feedback) Println(v ...interface{}) {
	s := fmt.Sprintln(v...)
	fmt.Print(s)
	LOG.Output(2, s)
}
Feedback is special. It writes plainly to the output while
logging with the standard extra information (date, file, etc)
Only Println and Printf are currently provided for this
package jwalterweatherman
import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"sync/atomic"
)
type Level int
type NotePad struct {
	Handle  io.Writer
	Level   Level
	Prefix  string
	Logger  **log.Logger
	counter uint64
}
func (n *NotePad) incr() {
	atomic.AddUint64(&n.counter, 1)
}
func (n *NotePad) resetCounter() {
	atomic.StoreUint64(&n.counter, 0)
}
func (n *NotePad) getCount() uint64 {
	return atomic.LoadUint64(&n.counter)
}
type countingWriter struct {
	incrFunc func()
}
func (cw *countingWriter) Write(p []byte) (n int, err error) {
	cw.incrFunc()
	return 0, nil
}
type Feedback struct{}
const (
	LevelTrace Level = iota
	LevelDebug
	LevelInfo
	LevelWarn
	LevelError
	LevelCritical
	LevelFatal
	DefaultLogThreshold    = LevelWarn
	DefaultStdoutThreshold = LevelError
)
var (
	TRACE      *log.Logger
	DEBUG      *log.Logger
	INFO       *log.Logger
	WARN       *log.Logger
	ERROR      *log.Logger
	CRITICAL   *log.Logger
	FATAL      *log.Logger
	LOG        *log.Logger
	FEEDBACK   Feedback
	LogHandle  io.Writer  = ioutil.Discard
	OutHandle  io.Writer  = os.Stdout
	BothHandle io.Writer  = io.MultiWriter(LogHandle, OutHandle)
	NotePads   []*NotePad = []*NotePad{trace, debug, info, warn, err, critical, fatal}
	trace           *NotePad = &NotePad{Level: LevelTrace, Handle: os.Stdout, Logger: &TRACE, Prefix: "TRACE: "}
	debug           *NotePad = &NotePad{Level: LevelDebug, Handle: os.Stdout, Logger: &DEBUG, Prefix: "DEBUG: "}
	info            *NotePad = &NotePad{Level: LevelInfo, Handle: os.Stdout, Logger: &INFO, Prefix: "INFO: "}
	warn            *NotePad = &NotePad{Level: LevelWarn, Handle: os.Stdout, Logger: &WARN, Prefix: "WARN: "}
	err             *NotePad = &NotePad{Level: LevelError, Handle: os.Stdout, Logger: &ERROR, Prefix: "ERROR: "}
	critical        *NotePad = &NotePad{Level: LevelCritical, Handle: os.Stdout, Logger: &CRITICAL, Prefix: "CRITICAL: "}
	fatal           *NotePad = &NotePad{Level: LevelFatal, Handle: os.Stdout, Logger: &FATAL, Prefix: "FATAL: "}
	logThreshold    Level    = DefaultLogThreshold
	outputThreshold Level    = DefaultStdoutThreshold
)
const (
	DATE  = log.Ldate
	TIME  = log.Ltime
	SFILE = log.Lshortfile
	LFILE = log.Llongfile
	MSEC  = log.Lmicroseconds
)
var logFlags = DATE | TIME | SFILE
func init() {
	SetStdoutThreshold(DefaultStdoutThreshold)
}
func initialize() {
	BothHandle = io.MultiWriter(LogHandle, OutHandle)
	for _, n := range NotePads {
		if n.Level < outputThreshold && n.Level < logThreshold {
			n.Handle = ioutil.Discard
		} else if n.Level >= outputThreshold && n.Level >= logThreshold {
			n.Handle = BothHandle
		} else if n.Level >= outputThreshold && n.Level < logThreshold {
			n.Handle = OutHandle
		} else {
			n.Handle = LogHandle
		}
	}
	for _, n := range NotePads {
		n.Handle = io.MultiWriter(n.Handle, &countingWriter{n.incr})
		*n.Logger = log.New(n.Handle, n.Prefix, logFlags)
	}
	LOG = log.New(LogHandle,
		"LOG:   ",
		logFlags)
}
func SetLogFlag(flags int) {
	logFlags = flags
	initialize()
}
func LogThreshold() Level {
	return logThreshold
}
func StdoutThreshold() Level {
	return outputThreshold
}
func levelCheck(level Level) Level {
	switch {
	case level <= LevelTrace:
		return LevelTrace
	case level >= LevelFatal:
		return LevelFatal
	default:
		return level
	}
}
func SetLogThreshold(level Level) {
	logThreshold = levelCheck(level)
	initialize()
}
func SetStdoutThreshold(level Level) {
	outputThreshold = levelCheck(level)
	initialize()
}
func SetLogFile(path string) {
	file, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		CRITICAL.Println("Failed to open log file:", path, err)
		os.Exit(-1)
	}
	INFO.Println("Logging to", file.Name())
	LogHandle = file
	initialize()
}
func UseTempLogFile(prefix string) {
	file, err := ioutil.TempFile(os.TempDir(), prefix)
	if err != nil {
		CRITICAL.Println(err)
	}
	INFO.Println("Logging to", file.Name())
	LogHandle = file
	initialize()
}
func LogCountForLevel(l Level) uint64 {
	for _, np := range NotePads {
		if np.Level == l {
			return np.getCount()
		}
	}
	return 0
}
func LogCountForLevelsGreaterThanorEqualTo(threshold Level) uint64 {
	var cnt uint64
	for _, np := range NotePads {
		if np.Level >= threshold {
			cnt += np.getCount()
		}
	}
	return cnt
}
func ResetLogCounters() {
	for _, np := range NotePads {
		np.resetCounter()
	}
}
func DiscardLogging() {
	LogHandle = ioutil.Discard
	initialize()
}