package log

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"runtime"
	"log"
)

// NewProduction builds a sensible production Logger that writes InfoLevel and
// above logs to standard error as JSON.
//
// It's a shortcut for NewProductionConfig().Build(...Option).
//
// Similar to zap.NewProduction with the modification to use ISO 8601 timestamps
// instead of unix timestamps.
func NewProduction(opts ...zap.Option) (*zap.Logger, error) {
	// return zap.NewProduction(opts)
	c := NewProductionConfig()
	return c.Build(opts...)
}

// NewDevelopment builds a development Logger that writes DebugLevel and above
// logs to standard error in a human-friendly format.
//
// It's a shortcut for NewDevelopmentConfig().Build(...Option).
func NewDevelopment(opts ...zap.Option) (*zap.Logger, error) {
	c := NewDevelopmentConfig()
	return c.Build(opts...)
}

// NewProductionConfig is the recommended production configuration. Logging is
// enabled at InfoLevel and above.
//
// It uses a JSON encoder, writes to standard error, and enables sampling.
// Stacktraces are automatically included on logs of ErrorLevel and above.
//
// Similar to zap.NewProductionConfig with the modification to use ISO 8601
// timestamps instead of unix timestamps.
func NewProductionConfig() zap.Config {
	// return zap.NewProductionConfig()
	c := zap.NewProductionConfig()
	c.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	return c
}

// NewDevelopmentConfig is a reasonable development configuration. Logging is
// enabled at DebugLevel and above.
//
// It enables development mode (which makes DPanicLevel logs panic), uses a
// console encoder, writes to standard error, and disables sampling.
// Stacktraces are automatically included on logs of WarnLevel and above.
func NewDevelopmentConfig() zap.Config {
	return zap.NewDevelopmentConfig()
}

// NewLevel returns a zapcore Level given a string. If the string is empty, INFO
// is returned. Returns an error for unknown log levels.
func NewLevel(level string) (zapcore.Level, error) {
	var l zapcore.Level
	err := l.Set(level)
	return l, err
}

// HandleError logs errors, used to handleError on defer
func HandleError(err error) {
	if err != nil {
		stack := make([]byte, 4<<10)          // 4 KB
		length := runtime.Stack(stack, false) // only current goroutine
		log.Printf("HandleError: %#v: %s", err, string(stack[:length]))
	}
}

