Update to v3.0.0-beta.4 - Logger changes book, examples updated

This commit is contained in:
Makis Maropoulos 2016-06-06 21:04:38 +03:00
parent 01b9e800d3
commit c88f73acbe
8 changed files with 223 additions and 231 deletions

View File

@ -6,7 +6,7 @@
[Travis]: http://travis-ci.org/kataras/iris
[License Widget]: https://img.shields.io/badge/license-Apache%20License%202.0-E91E63.svg?style=flat-square
[License]: https://github.com/kataras/iris/blob/master/LICENSE
[Release Widget]: https://img.shields.io/badge/release-v3.0.0--beta.3-blue.svg?style=flat-square
[Release Widget]: https://img.shields.io/badge/release-v3.0.0--beta.4-blue.svg?style=flat-square
[Release]: https://github.com/kataras/iris/releases
[Gitter Widget]: https://img.shields.io/badge/chat-on%20gitter-00BCD4.svg?style=flat-square
[Gitter]: https://gitter.im/kataras/iris
@ -116,7 +116,7 @@ Iris suggests you to use [this](https://github.com/gavv/httpexpect) new suite t
Versioning
------------
Current: **v3.0.0-beta.3**
Current: **v3.0.0-beta.4**
> Iris is an active project

View File

@ -21,12 +21,6 @@ type (
// using Config().Sessions...
// and so on...
Iris struct {
// MaxRequestBodySize Maximum request body size.
//
// The server rejects requests with bodies exceeding this limit.
//
// By default request body size is -1, unlimited.
MaxRequestBodySize int64
// DisablePathCorrection corrects and redirects the requested path to the registed path
// for example, if /home/ path is requested but no handler for this Route found,
@ -50,15 +44,18 @@ type (
// Default is false
DisablePathEscape bool
// DisableLog turn it to true if you want to disable logger,
// Iris prints/logs ONLY errors, so be careful when you enable it
DisableLog bool
// DisableBanner outputs the iris banner at startup
//
// Default is false
DisableBanner bool
// MaxRequestBodySize Maximum request body size.
//
// The server rejects requests with bodies exceeding this limit.
//
// By default request body size is -1, unlimited.
MaxRequestBodySize int64
// Profile set to true to enable web pprof (debug profiling)
// Default is false, enabling makes available these 7 routes:
// /debug/pprof/cmdline
@ -74,6 +71,10 @@ type (
// Default is /debug/pprof , which means yourhost.com/debug/pprof
ProfilePath string
// Logger the configuration for the logger
// Iris logs ONLY errors and the banner if enabled
Logger Logger
// Sessions the config for sessions
// contains 3(three) properties
// Provider: (look /sessions/providers)
@ -86,6 +87,7 @@ type (
// Websocket contains the configs for Websocket's server integration
Websocket Websocket
// Mail contains the config for the mail sender service
Mail Mail
}
@ -117,11 +119,10 @@ func Default() Iris {
return Iris{
DisablePathCorrection: false,
DisablePathEscape: false,
MaxRequestBodySize: -1,
DisableLog: false,
DisableBanner: false,
Profile: false,
MaxRequestBodySize: -1,
ProfilePath: DefaultProfilePath,
Logger: DefaultLogger(),
Sessions: DefaultSessions(),
Render: DefaultRender(),
Websocket: DefaultWebsocket(),

View File

@ -1,43 +1,85 @@
package config
import "github.com/imdario/mergo"
import (
"github.com/fatih/color"
"github.com/imdario/mergo"
)
import (
"io"
"os"
)
const DefaultLoggerPrefix = "[IRIS] "
var (
// TimeFormat default time format for any kind of datetime parsing
TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
)
type (
// Logger contains the configs for the Logger
// Logger contains the full configuration options fields for the Logger
Logger struct {
Out io.Writer
// Out the (file) writer which the messages/logs will printed to
// Default is os.Stdout
Out *os.File
// Prefix the prefix for each message
Prefix string
Flag int
// Disabled default is false
Disabled bool
// foreground colors single SGR Code
// ColorFgDefault the foreground color for the normal message bodies
ColorFgDefault int
// ColorFgInfo the foreground color for info messages
ColorFgInfo int
// ColorFgSuccess the foreground color for success messages
ColorFgSuccess int
// ColorFgWarning the foreground color for warning messages
ColorFgWarning int
// ColorFgDanger the foreground color for error messages
ColorFgDanger int
// background colors single SGR Code
// ColorBgDefault the background color for the normal message bodies
ColorBgDefault int
// ColorBgInfo the background color for info messages
ColorBgInfo int
// ColorBgSuccess the background color for success messages
ColorBgSuccess int
// ColorBgWarning the background color for warning messages
ColorBgWarning int
// ColorBgDanger the background color for error messages
ColorBgDanger int
// banners are the force printed/written messages, doesn't care about Disabled field
// ColorFgBanner the foreground color for the banner
ColorFgBanner int
}
)
// DefaultLogger returns the default configs for the Logger
func DefaultLogger() Logger {
return Logger{Out: os.Stdout, Prefix: "", Flag: 0}
}
// Merge merges the default with the given config and returns the result
func (c Logger) Merge(cfg []Logger) (config Logger) {
if len(cfg) > 0 {
config = cfg[0]
mergo.Merge(&config, c)
} else {
_default := c
config = _default
return Logger{
Out: os.Stdout,
Prefix: DefaultLoggerPrefix,
Disabled: false,
// foreground colors
ColorFgDefault: int(color.FgHiWhite),
ColorFgInfo: int(color.FgCyan),
ColorFgSuccess: int(color.FgHiGreen),
ColorFgWarning: int(color.FgHiMagenta),
ColorFgDanger: int(color.FgHiRed),
// background colors
ColorBgDefault: int(color.BgHiBlack),
ColorBgInfo: int(color.BgHiBlack),
ColorBgSuccess: int(color.BgHiBlack),
ColorBgWarning: int(color.BgHiBlack),
ColorBgDanger: int(color.BgHiWhite),
// banner colors
ColorFgBanner: int(color.FgHiBlue),
}
return
}
// MergeSingle merges the default with the given config and returns the result

View File

@ -192,9 +192,9 @@ func (srv *Server) StopChan() <-chan struct{} {
}
// DefaultLogger returns the logger used by Run, RunWithErr, ListenAndServe, ListenAndServeTLS and Serve.
// The logger outputs to STDERR by default.
// The logger outputs to STDOUT by default.
func DefaultLogger() *logger.Logger {
return logger.New()
return logger.New(config.DefaultLogger())
}
func (srv *Server) manageConnections(add, remove chan net.Conn, shutdown chan chan struct{}, kill chan struct{}) {

76
iris.go
View File

@ -5,12 +5,9 @@ package iris
import (
"os"
"strconv"
"sync"
"sync/atomic"
"time"
"github.com/fatih/color"
"github.com/kataras/iris/config"
"github.com/kataras/iris/logger"
"github.com/kataras/iris/mail"
@ -21,21 +18,22 @@ import (
// memory loads the memory session provider
_ "github.com/kataras/iris/sessions/providers/memory"
// _ redis loads the redis session provider
"fmt"
_ "github.com/kataras/iris/sessions/providers/redis"
"github.com/kataras/iris/utils"
"github.com/kataras/iris/websocket"
"github.com/klauspost/compress/gzip"
)
const (
// Version of the iris
Version = "v3.0.0-beta.3"
banner = ` _____ _
|_ _| (_)
| | ____ _ ___
| | | __|| |/ __|
_| |_| | | |\__ \
|_____|_| |_||___/ ` + Version + `
Version = "v3.0.0-beta.4"
banner = ` _____ _
|_ _| (_)
| | ____ _ ___
| | | __|| |/ __|
_| |_| | | |\__ \
|_____|_| |_||___/ ` + Version + `
`
)
@ -64,8 +62,6 @@ var (
/* */
var stationsRunning = 0
type (
// Iris is the container of all, server, router, cache and the sync.Pool
@ -99,7 +95,7 @@ func New(cfg ...config.Iris) *Iris {
s.router = newRouter(s)
// set the Logger
s.logger = logger.New()
s.logger = logger.New(c.Logger)
//set the plugin container
s.plugins = &PluginContainer{logger: s.logger}
@ -152,60 +148,12 @@ func (s *Iris) initMailService() {
}
}
func (s *Iris) printBanner() {
c := color.New(color.FgHiBlue).Add(color.Bold)
printTicker := utils.NewTicker()
// for ANY case, we don't want to panic on print banner if anything goes bad
defer func() {
if r := recover(); r != nil {
printTicker.Stop()
}
}()
var i uint64
printTicker.OnTick(func() {
if len(banner) <= int(atomic.LoadUint64(&i)) {
atomic.StoreUint64(&i, 0)
printTicker.Stop()
c.Add(color.FgGreen)
stationsRunning++
c.Println()
if s.server != nil && s.server.IsListening() {
if stationsRunning > 1 {
c.Println("Server[" + strconv.Itoa(stationsRunning) + "]")
}
c.Printf("%s: Running at %s\n", time.Now().Format(config.TimeFormat), s.server.Config.ListeningAddr)
}
c.DisableColor()
return
}
c.Printf("%c", banner[i])
atomic.AddUint64(&i, 1)
})
printTicker.Start(time.Duration(433) * time.Nanosecond)
}
// PreListen call router's optimize, sets the server's handler and notice the plugins
// capital because we need it sometimes, for example inside the graceful
// receives the config.Server
// returns the station's Server (*server.Server)
// it's a non-blocking func
func (s *Iris) PreListen(opt config.Server) *server.Server {
// run the printBanner with nice animation until PreListen and PostListen finish
if !s.config.DisableBanner {
go s.printBanner()
}
// set the logger's state
s.logger.SetEnable(!s.config.DisableLog)
// router preparation, runs only once even if called more than one time.
if !s.router.optimized {
s.router.optimize()
@ -218,6 +166,10 @@ func (s *Iris) PreListen(opt config.Server) *server.Server {
}
}
if !s.config.DisableBanner {
s.logger.PrintBanner(banner, fmt.Sprintf("%s: Running at %s\n", time.Now().Format(config.TimeFormat), s.server.Config.ListeningAddr))
}
s.plugins.DoPreListen(s)
return s.server

View File

@ -1,111 +1,191 @@
package logger
import (
"log"
"os"
"github.com/fatih/color"
"github.com/kataras/iris/config"
"github.com/mattn/go-colorable"
)
var (
// Prefix is the prefix for the logger, default is [IRIS]
Prefix = "[IRIS] "
// bannersRan keeps track of the logger's print banner count
bannersRan = 0
)
// Logger is just a log.Logger
// Logger the logger
type Logger struct {
Logger *log.Logger
enabled bool
config config.Logger
underline *color.Color
}
// New creates a new Logger. The out variable sets the
// destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func New(cfg ...config.Logger) *Logger {
c := config.DefaultLogger().Merge(cfg)
return &Logger{Logger: log.New(c.Out, Prefix+c.Prefix, c.Flag), enabled: true}
// attr takes a color integer and converts it to color.Attribute
func attr(sgr int) color.Attribute {
return color.Attribute(sgr)
}
// New creates a new Logger from config.Logger configuration
func New(c config.Logger) *Logger {
color.Output = colorable.NewColorable(c.Out)
l := &Logger{c, color.New(attr(c.ColorBgDefault), attr(c.ColorFgDefault), color.Bold)}
return l
}
// PrintBanner prints a text (banner) with BannerFgColor, BannerBgColor and a success message at the end
// It doesn't cares if the logger is disabled or not, it will print this
func (l *Logger) PrintBanner(banner string, sucessMessage string) {
c := color.New(attr(l.config.ColorBgDefault), attr(l.config.ColorFgBanner), color.Bold)
c.Println(banner)
bannersRan++
if sucessMessage != "" {
c.Add(attr(l.config.ColorBgSuccess), attr(l.config.ColorFgSuccess), color.Bold)
if bannersRan > 1 {
c.Printf("Server[%#v]\n", bannersRan)
}
c.Println(sucessMessage)
}
c.DisableColor()
c = nil
}
// ResetColors sets the colors to the default
// this func is called every time a success, info, warning, or danger message is printed
func (l *Logger) ResetColors() {
l.underline.Add(attr(l.config.ColorBgDefault), attr(l.config.ColorFgBanner), color.Bold)
}
// SetEnable true enables, false disables the Logger
func (l *Logger) SetEnable(enable bool) {
l.enabled = enable
l.config.Disabled = !enable
}
// IsEnabled returns true if Logger is enabled, otherwise false
func (l *Logger) IsEnabled() bool {
return l.enabled
return !l.config.Disabled
}
// Print calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Print(v ...interface{}) {
if l.enabled {
l.Logger.Print(v...)
if !l.config.Disabled {
l.underline.Print(v...)
}
}
// Printf calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Printf(format string, a ...interface{}) {
if l.enabled {
l.Logger.Printf(format, a...)
if !l.config.Disabled {
l.underline.Printf(format, a...)
}
}
// Println calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Println.
func (l *Logger) Println(a ...interface{}) {
if l.enabled {
l.Logger.Println(a...)
if !l.config.Disabled {
l.underline.Println(a...)
}
}
// Fatal is equivalent to l.Print() followed by a call to os.Exit(1).
func (l *Logger) Fatal(a ...interface{}) {
if l.enabled {
l.Logger.Fatal(a...)
} else {
os.Exit(1) //we have to exit at any case because this is the Fatal
if !l.config.Disabled {
l.underline.Print(a...)
}
os.Exit(1)
}
// Fatalf is equivalent to l.Printf() followed by a call to os.Exit(1).
func (l *Logger) Fatalf(format string, a ...interface{}) {
if l.enabled {
l.Logger.Fatalf(format, a...)
} else {
os.Exit(1)
if !l.config.Disabled {
l.underline.Printf(format, a...)
}
os.Exit(1)
}
// Fatalln is equivalent to l.Println() followed by a call to os.Exit(1).
func (l *Logger) Fatalln(a ...interface{}) {
if l.enabled {
l.Logger.Fatalln(a...)
} else {
os.Exit(1)
if !l.config.Disabled {
l.underline.Println(a...)
}
os.Exit(1)
}
// Panic is equivalent to l.Print() followed by a call to panic().
func (l *Logger) Panic(a ...interface{}) {
if l.enabled {
l.Logger.Panic(a...)
if !l.config.Disabled {
l.underline.Print(a...)
}
panic("")
}
// Panicf is equivalent to l.Printf() followed by a call to panic().
func (l *Logger) Panicf(format string, a ...interface{}) {
if l.enabled {
l.Logger.Panicf(format, a...)
if !l.config.Disabled {
l.underline.Printf(format, a...)
}
panic("")
}
// Panicln is equivalent to l.Println() followed by a call to panic().
func (l *Logger) Panicln(a ...interface{}) {
if l.enabled {
l.Logger.Panicln(a...)
if !l.config.Disabled {
l.underline.Println(a...)
}
panic("")
}
// Sucessf calls l.Output to print to the logger with the Success colors.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Sucessf(format string, a ...interface{}) {
if !l.config.Disabled {
l.underline.Add(attr(l.config.ColorBgSuccess), attr(l.config.ColorFgSuccess))
l.underline.Printf(format, a...)
l.ResetColors()
}
}
// Infof calls l.Output to print to the logger with the Info colors.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Infof(format string, a ...interface{}) {
if !l.config.Disabled {
l.underline.Add(attr(l.config.ColorBgInfo), attr(l.config.ColorFgInfo))
l.underline.Printf(format, a...)
l.ResetColors()
}
}
// Warningf calls l.Output to print to the logger with the Warning colors.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Warningf(format string, a ...interface{}) {
if !l.config.Disabled {
l.underline.Add(attr(l.config.ColorBgWarning), attr(l.config.ColorFgWarning))
l.underline.Printf(format, a...)
l.ResetColors()
}
}
// Dangerf calls l.Output to print to the logger with the Danger colors.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Dangerf(format string, a ...interface{}) {
if !l.config.Disabled {
l.underline.Add(attr(l.config.ColorBgDanger), attr(l.config.ColorFgDanger))
l.underline.Printf(format, a...)
l.ResetColors()
}
}

View File

@ -1,64 +1,9 @@
## Middleware information
This folder contains a middleware for the build'n Iris logger but for the requests.
This folder contains a middleware which is a bridge between Iris station's logger and http requests.
**Logs the incoming requests**
## How to use
```go
package main
import (
"github.com/kataras/iris"
"github.com/kataras/iris/middleware/logger"
)
func main() {
iris.UseFunc(logger.Default())
// or iris.Use(logger.DefaultHandler())
// or iris.UseFunc(iris.HandlerFunc(logger.DefaultHandler())
// or iris.Get("/", logger.Default(), func (ctx *iris.Context){})
// or iris.Get("/", iris.HandlerFunc(logger.DefaultHandler()), func (ctx *iris.Context){})
// Custom settings:
// ...
// iris.UseFunc(logger.Custom(writer io.Writer, prefix string, flag int))
// and so on...
// Custom options:
// ...
// iris.UseFunc(logger.Default(logger.Options{IP:false})) // don't log the ip
// or iris.UseFunc(logger.Custom(writer io.Writer, prefix string, flag int, logger.Options{IP:false}))
// and so on...
iris.Get("/", func(ctx *iris.Context) {
ctx.Write("hello")
})
iris.Get("/1", func(ctx *iris.Context) {
ctx.Write("hello")
})
iris.Get("/3", func(ctx *iris.Context) {
ctx.Write("hello")
})
// IF YOU WANT LOGGER TO LOGS THE HTTP ERRORS ALSO THEN:
// FUTURE: iris.OnError(404, logger.Default(logger.Options{Latency: false}))
// NOW:
errorLogger := logger.Default(logger.Options{Latency: false}) //here we just disable to log the latency, no need for error pages I think
// yes we have options look at the logger.Options inside middleware/logger.go
iris.OnError(404, func(ctx *iris.Context) {
errorLogger.Serve(ctx)
ctx.Write("My Custom 404 error page ")
})
//
println("Server is running at :80")
iris.Listen(":80")
}
```
Read the logger section [here](https://kataras.gitbooks.io/iris/content/logger.html)

View File

@ -75,17 +75,20 @@ func (l *loggerMiddleware) Serve(ctx *iris.Context) {
//finally print the logs
if l.options.Latency {
l.Printf("%s %v %4v %s %s %s", date, status, latency, ip, method, path)
l.Infof("%s %v %4v %s %s %s \n", date, status, latency, ip, method, path)
} else {
l.Printf("%s %v %s %s %s", date, status, ip, method, path)
l.Infof("%s %v %s %s %s \n", date, status, ip, method, path)
}
}
func newLoggerMiddleware(loggerCfg config.Logger, options ...Options) *loggerMiddleware {
loggerCfg = config.DefaultLogger().MergeSingle(loggerCfg)
// Default returns the logger middleware as Handler with the default settings
func New(theLogger *logger.Logger, options ...Options) iris.HandlerFunc {
if theLogger == nil {
theLogger = logger.New(config.DefaultLogger())
}
l := &loggerMiddleware{Logger: logger.New(loggerCfg)}
l := &loggerMiddleware{Logger: theLogger}
if len(options) > 0 {
l.options = options[0]
@ -93,36 +96,5 @@ func newLoggerMiddleware(loggerCfg config.Logger, options ...Options) *loggerMid
l.options = DefaultOptions()
}
return l
}
//all bellow are just for flexibility
// DefaultHandler returns the logger middleware with the default settings
func DefaultHandler(options ...Options) iris.Handler {
loggerCfg := config.DefaultLogger()
return newLoggerMiddleware(loggerCfg, options...)
}
// Default returns the logger middleware as HandlerFunc with the default settings
func Default(options ...Options) iris.HandlerFunc {
return DefaultHandler(options...).Serve
}
// CustomHandler returns the logger middleware with customized settings
// accepts 3 parameters
// first parameter is the writer (io.Writer)
// second parameter is the prefix of which the message will follow up
// third parameter is the logger.Options
func CustomHandler(loggerCfg config.Logger, options ...Options) iris.Handler {
return newLoggerMiddleware(loggerCfg, options...)
}
// Custom returns the logger middleware as HandlerFunc with customized settings
// accepts 3 parameters
// first parameter is the writer (io.Writer)
// second parameter is the prefix of which the message will follow up
// third parameter is the logger.Options
func Custom(loggerCfg config.Logger, options ...Options) iris.HandlerFunc {
return CustomHandler(loggerCfg, options...).Serve
return l.Serve
}