github.com/wiselike/revel-cmd@v1.2.1/logger/init.go (about)

     1  package logger
     2  
     3  // Get all handlers based on the Config (if available).
     4  import (
     5  	"fmt"
     6  	"log"
     7  	"os"
     8  	"path/filepath"
     9  	"strings"
    10  
    11  	"github.com/revel/config"
    12  )
    13  
    14  func InitializeFromConfig(basePath string, config *config.Context) (c *CompositeMultiHandler) {
    15  	// If running in test mode suppress anything that is not an error
    16  	if config != nil && config.BoolDefault(TestModeFlag, false) {
    17  		// Preconfigure all the options
    18  		config.SetOption("log.info.output", "none")
    19  		config.SetOption("log.debug.output", "none")
    20  		config.SetOption("log.warn.output", "none")
    21  		config.SetOption("log.error.output", "stderr")
    22  		config.SetOption("log.crit.output", "stderr")
    23  	}
    24  
    25  	// If the configuration has an all option we can skip some
    26  	c, _ = NewCompositeMultiHandler()
    27  
    28  	// Filters are assigned first, non filtered items override filters
    29  	if config != nil && !config.BoolDefault(TestModeFlag, false) {
    30  		initAllLog(c, basePath, config)
    31  	}
    32  	initLogLevels(c, basePath, config)
    33  	if c.CriticalHandler == nil && c.ErrorHandler != nil {
    34  		c.CriticalHandler = c.ErrorHandler
    35  	}
    36  	if config != nil && !config.BoolDefault(TestModeFlag, false) {
    37  		initFilterLog(c, basePath, config)
    38  		if c.CriticalHandler == nil && c.ErrorHandler != nil {
    39  			c.CriticalHandler = c.ErrorHandler
    40  		}
    41  		initRequestLog(c, basePath, config)
    42  	}
    43  
    44  	return c
    45  }
    46  
    47  // Init the log.all configuration options.
    48  func initAllLog(c *CompositeMultiHandler, basePath string, config *config.Context) {
    49  	if config != nil {
    50  		extraLogFlag := config.BoolDefault(SpecialUseFlag, false)
    51  		if output, found := config.String("log.all.output"); found {
    52  			// Set all output for the specified handler
    53  			if extraLogFlag {
    54  				log.Printf("Adding standard handler for levels to >%s< ", output)
    55  			}
    56  			initHandlerFor(c, output, basePath, NewLogOptions(config, true, nil, LvlAllList...))
    57  		}
    58  	}
    59  }
    60  
    61  // Init the filter options
    62  // log.all.filter ....
    63  // log.error.filter ....
    64  func initFilterLog(c *CompositeMultiHandler, basePath string, config *config.Context) {
    65  	if config != nil {
    66  		extraLogFlag := config.BoolDefault(SpecialUseFlag, false)
    67  
    68  		for _, logFilter := range logFilterList {
    69  			// Init for all filters
    70  			for _, name := range []string{
    71  				"all", "debug", "info", "warn", "error", "crit",
    72  				"trace", // TODO trace is deprecated
    73  			} {
    74  				optionList := config.Options(logFilter.LogPrefix + name + logFilter.LogSuffix)
    75  				for _, option := range optionList {
    76  					splitOptions := strings.Split(option, ".")
    77  					keyMap := map[string]interface{}{}
    78  					for x := 3; x < len(splitOptions); x += 2 {
    79  						keyMap[splitOptions[x]] = splitOptions[x+1]
    80  					}
    81  					phandler := logFilter.parentHandler(keyMap)
    82  					if extraLogFlag {
    83  						log.Printf("Adding key map handler %s %s output %s", option, name, config.StringDefault(option, ""))
    84  						fmt.Printf("Adding key map handler %s %s output %s matching %#v\n", option, name, config.StringDefault(option, ""), keyMap)
    85  					}
    86  
    87  					if name == "all" {
    88  						initHandlerFor(c, config.StringDefault(option, ""), basePath, NewLogOptions(config, false, phandler))
    89  					} else {
    90  						initHandlerFor(c, config.StringDefault(option, ""), basePath, NewLogOptions(config, false, phandler, toLevel[name]))
    91  					}
    92  				}
    93  			}
    94  		}
    95  	}
    96  }
    97  
    98  // Init the log.error, log.warn etc configuration options.
    99  func initLogLevels(c *CompositeMultiHandler, basePath string, config *config.Context) {
   100  	for _, name := range []string{
   101  		"debug", "info", "warn", "error", "crit",
   102  		"trace", // TODO trace is deprecated
   103  	} {
   104  		if config != nil {
   105  			extraLogFlag := config.BoolDefault(SpecialUseFlag, false)
   106  			output, found := config.String("log." + name + ".output")
   107  			if found {
   108  				if extraLogFlag {
   109  					log.Printf("Adding standard handler %s output %s", name, output)
   110  				}
   111  				initHandlerFor(c, output, basePath, NewLogOptions(config, true, nil, toLevel[name]))
   112  			}
   113  			// Gets the list of options with said prefix
   114  		} else {
   115  			initHandlerFor(c, "stderr", basePath, NewLogOptions(config, true, nil, toLevel[name]))
   116  		}
   117  	}
   118  }
   119  
   120  // Init the request log options.
   121  func initRequestLog(c *CompositeMultiHandler, basePath string, config *config.Context) {
   122  	// Request logging to a separate output handler
   123  	// This takes the InfoHandlers and adds a MatchAbHandler handler to it to direct
   124  	// context with the word "section=requestlog" to that handler.
   125  	// Note if request logging is not enabled the MatchAbHandler will not be added and the
   126  	// request log messages will be sent out the INFO handler
   127  	outputRequest := "stdout"
   128  	if config != nil {
   129  		outputRequest = config.StringDefault("log.request.output", "")
   130  	}
   131  	oldInfo := c.InfoHandler
   132  	c.InfoHandler = nil
   133  	if outputRequest != "" {
   134  		initHandlerFor(c, outputRequest, basePath, NewLogOptions(config, false, nil, LvlInfo))
   135  	}
   136  	if c.InfoHandler != nil || oldInfo != nil {
   137  		if c.InfoHandler == nil {
   138  			c.InfoHandler = oldInfo
   139  		} else {
   140  			c.InfoHandler = MatchAbHandler("section", "requestlog", c.InfoHandler, oldInfo)
   141  		}
   142  	}
   143  }
   144  
   145  // Returns a handler for the level using the output string
   146  // Accept formats for output string are
   147  // LogFunctionMap[value] callback function
   148  // `stdout` `stderr` `full/file/path/to/location/app.log` `full/file/path/to/location/app.json`.
   149  func initHandlerFor(c *CompositeMultiHandler, output, basePath string, options *LogOptions) {
   150  	if options.Ctx != nil {
   151  		options.SetExtendedOptions(
   152  			"noColor", !options.Ctx.BoolDefault("log.colorize", true),
   153  			"smallDate", options.Ctx.BoolDefault("log.smallDate", true),
   154  			"maxSize", options.Ctx.IntDefault("log.maxsize", 1024*10),
   155  			"maxAge", options.Ctx.IntDefault("log.maxage", 14),
   156  			"maxBackups", options.Ctx.IntDefault("log.maxbackups", 14),
   157  			"compressBackups", !options.Ctx.BoolDefault("log.compressBackups", true),
   158  		)
   159  	}
   160  
   161  	output = strings.TrimSpace(output)
   162  	if funcHandler, found := LogFunctionMap[output]; found {
   163  		funcHandler(c, options)
   164  	} else {
   165  		switch output {
   166  		case "":
   167  			fallthrough
   168  		case "off":
   169  		// No handler, discard data
   170  		default:
   171  			// Write to file specified
   172  			if !filepath.IsAbs(output) {
   173  				output = filepath.Join(basePath, output)
   174  			}
   175  
   176  			if err := os.MkdirAll(filepath.Dir(output), 0755); err != nil {
   177  				log.Panic(err)
   178  			}
   179  
   180  			if strings.HasSuffix(output, "json") {
   181  				c.SetJSONFile(output, options)
   182  			} else {
   183  				// Override defaults for a terminal file
   184  				options.SetExtendedOptions("noColor", true)
   185  				options.SetExtendedOptions("smallDate", false)
   186  				c.SetTerminalFile(output, options)
   187  			}
   188  		}
   189  	}
   190  }