func (fl FieldLogger) Info(msg string, fields ...LoggableField) {
	fl.l.Info(msg, unpack(append(fields, String("name", fl.name)))...)
}
note: we construct the fieldset on the fly, below, rather than simply adding `name' as a field since it may change
if a child logger is created from a parent. once a field has been added to a logger it cannot be changed or removed.
see WithName, above.
Info prints message with fields.
package log
import (
	"context"
	"fmt"
	"reflect"
	"runtime/debug"
	"strings"
	"time"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)
type Log struct {
	logger *zap.Logger
	name   string
}
func (l Log) Info(format string, args ...interface{}) {
	l.logger.Sugar().Infof(format, args...)
}
func (l Log) Debug(format string, args ...interface{}) {
	l.logger.Sugar().Debugf(format, args...)
}
func (l Log) Error(format string, args ...interface{}) {
	l.logger.Sugar().Errorf(format, args...)
}
func (l Log) Warning(format string, args ...interface{}) {
	l.logger.Sugar().Warnf(format, args...)
}
func (l Log) Panic(format string, args ...interface{}) {
	l.logger.Sugar().Error("Fatal: goroutine panicked. Stacktrace: ", string(debug.Stack()))
	l.logger.Sugar().Panicf(format, args...)
}
type Field zap.Field
func (f Field) Field() Field { return f }
func FieldNamed(name string, field LoggableField) Field {
	if field == nil || (reflect.ValueOf(field).Kind() == reflect.Ptr && reflect.ValueOf(field).IsNil()) {
		return String(name, "nil")
	}
	f := field.Field()
	f.Key = name
	return f
}
func String(name, val string) Field {
	return Field(zap.String(name, val))
}
func Binary(name string, val []byte) Field {
	return Field(zap.Binary(name, val))
}
func Int(name string, val int) Field {
	return Field(zap.Int(name, val))
}
func Int32(name string, val int32) Field {
	return Field(zap.Int32(name, val))
}
func Uint16(name string, val uint16) Field {
	return Field(zap.Uint16(name, val))
}
func Uint32(name string, val uint32) Field {
	return Field(zap.Uint32(name, val))
}
func Uint64(name string, val uint64) Field {
	return Field(zap.Uint64(name, val))
}
func Namespace(name string) Field {
	return Field(zap.Namespace(name))
}
func Bool(name string, val bool) Field {
	return Field(zap.Bool(name, val))
}
func Time(name string, val time.Time) Field {
	return Field(zap.Time(name, val))
}
func Duration(name string, val time.Duration) Field {
	return Field(zap.Duration(name, val))
}
func Err(v error) Field {
	return Field(zap.NamedError("errmsg", v))
}
type LoggableField interface {
	Field() Field
}
func unpack(fields []LoggableField) []zap.Field {
	flds := make([]zap.Field, len(fields))
	for i, f := range fields {
		flds[i] = zap.Field(f.Field())
	}
	return flds
}
type FieldLogger struct {
	l    *zap.Logger
	name string
}
func (l Log) With() FieldLogger {
	return FieldLogger{l.logger, l.name}
}
func (l Log) SetLevel(level *zap.AtomicLevel) Log {
	if willWrite := l.logger.Check(level.Level(), "test"); willWrite == nil {
		Warning("attempt to SetLevel of logger lower than parent level, this may result in " +
			"log entries being dropped silently")
	}
	lgr := l.logger.WithOptions(zap.IncreaseLevel(level))
	return Log{logger: lgr, name: l.name}
}
func (l Log) Check(level zapcore.Level) bool {
	return l.logger.Check(level, "") != nil
}
func (l Log) Core() zapcore.Core {
	return l.logger.Core()
}
func (l Log) WithName(prefix string) Log {
	lgr := l.logger.Named(fmt.Sprintf("%-13s", prefix))
	var name string
	if l.name == "" {
		name = prefix
	} else {
		name = strings.Join([]string{l.name, prefix}, ".")
	}
	return Log{logger: lgr, name: name}
}
func (l Log) Named(name string) Log {
	return NewFromLog(l.logger.Named(name))
}
func (l Log) WithFields(fields ...LoggableField) Log {
	lgr := l.logger.With(unpack(fields)...)
	return Log{logger: lgr, name: l.name}
}
func (l Log) WithContext(ctx context.Context) Log {
	var fields []LoggableField
	if ctx != nil {
		if ctxRequestID, ok := ExtractRequestID(ctx); ok {
			fields = append(fields, append(ExtractRequestFields(ctx), String("requestId", ctxRequestID))...)
		}
		if ctxSessionID, ok := ExtractSessionID(ctx); ok {
			fields = append(fields, append(ExtractSessionFields(ctx), String("sessionId", ctxSessionID))...)
		}
	}
	return l.WithFields(fields...)
}
const eventKey = "event"
func (l Log) Event() FieldLogger {
	return FieldLogger{l: l.logger.With(zap.Field(Bool(eventKey, true))), name: l.name}
}
var Nop = zap.WrapCore(func(zapcore.Core) zapcore.Core {
	return zapcore.NewNopCore()
})
func (l Log) WithOptions(opts ...zap.Option) Log {
	lgr := l.logger.WithOptions(opts...)
	return Log{logger: lgr, name: l.name}
}