3 // Get all handlers based on the Config (if available)
6 "github.com/revel/config"
13 func InitializeFromConfig(basePath string, config *config.Context) (c *CompositeMultiHandler) {
14 // If running in test mode suppress anything that is not an error
15 if config != nil && config.BoolDefault(TEST_MODE_FLAG, false) {
16 // Preconfigure all the options
17 config.SetOption("log.info.output", "none")
18 config.SetOption("log.debug.output", "none")
19 config.SetOption("log.warn.output", "none")
20 config.SetOption("log.error.output", "stderr")
21 config.SetOption("log.crit.output", "stderr")
24 // If the configuration has an all option we can skip some
25 c, _ = NewCompositeMultiHandler()
27 // Filters are assigned first, non filtered items override filters
28 if config != nil && !config.BoolDefault(TEST_MODE_FLAG, false) {
29 initAllLog(c, basePath, config)
31 initLogLevels(c, basePath, config)
32 if c.CriticalHandler == nil && c.ErrorHandler != nil {
33 c.CriticalHandler = c.ErrorHandler
35 if config != nil && !config.BoolDefault(TEST_MODE_FLAG, false) {
36 initFilterLog(c, basePath, config)
37 if c.CriticalHandler == nil && c.ErrorHandler != nil {
38 c.CriticalHandler = c.ErrorHandler
40 initRequestLog(c, basePath, config)
46 // Init the log.all configuration options
47 func initAllLog(c *CompositeMultiHandler, basePath string, config *config.Context) {
49 extraLogFlag := config.BoolDefault(SPECIAL_USE_FLAG, false)
50 if output, found := config.String("log.all.output"); found {
51 // Set all output for the specified handler
53 log.Printf("Adding standard handler for levels to >%s< ", output)
55 initHandlerFor(c, output, basePath, NewLogOptions(config, true, nil, LvlAllList...))
60 // Init the filter options
61 // log.all.filter ....
62 // log.error.filter ....
63 func initFilterLog(c *CompositeMultiHandler, basePath string, config *config.Context) {
66 extraLogFlag := config.BoolDefault(SPECIAL_USE_FLAG, false)
68 for _, logFilter := range logFilterList {
69 // Init for all filters
70 for _, name := range []string{"all", "debug", "info", "warn", "error", "crit",
71 "trace", // TODO trace is deprecated
73 optionList := config.Options(logFilter.LogPrefix + name + logFilter.LogSuffix)
74 for _, option := range optionList {
75 splitOptions := strings.Split(option, ".")
76 keyMap := map[string]interface{}{}
77 for x := 3; x < len(splitOptions); x += 2 {
78 keyMap[splitOptions[x]] = splitOptions[x+1]
80 phandler := logFilter.parentHandler(keyMap)
82 log.Printf("Adding key map handler %s %s output %s", option, name, config.StringDefault(option, ""))
83 fmt.Printf("Adding key map handler %s %s output %s matching %#v\n", option, name, config.StringDefault(option, ""), keyMap)
87 initHandlerFor(c, config.StringDefault(option, ""), basePath, NewLogOptions(config, false, phandler))
89 initHandlerFor(c, config.StringDefault(option, ""), basePath, NewLogOptions(config, false, phandler, toLevel[name]))
97 // Init the log.error, log.warn etc configuration options
98 func initLogLevels(c *CompositeMultiHandler, basePath string, config *config.Context) {
99 for _, name := range []string{"debug", "info", "warn", "error", "crit",
100 "trace", // TODO trace is deprecated
103 extraLogFlag := config.BoolDefault(SPECIAL_USE_FLAG, false)
104 output, found := config.String("log." + name + ".output")
107 log.Printf("Adding standard handler %s output %s", name, output)
109 initHandlerFor(c, output, basePath, NewLogOptions(config, true, nil, toLevel[name]))
111 // Gets the list of options with said prefix
113 initHandlerFor(c, "stderr", basePath, NewLogOptions(config, true, nil, toLevel[name]))
118 // Init the request log options
119 func initRequestLog(c *CompositeMultiHandler, basePath string, config *config.Context) {
120 // Request logging to a separate output handler
121 // This takes the InfoHandlers and adds a MatchAbHandler handler to it to direct
122 // context with the word "section=requestlog" to that handler.
123 // Note if request logging is not enabled the MatchAbHandler will not be added and the
124 // request log messages will be sent out the INFO handler
125 outputRequest := "stdout"
127 outputRequest = config.StringDefault("log.request.output", "")
129 oldInfo := c.InfoHandler
131 if outputRequest != "" {
132 initHandlerFor(c, outputRequest, basePath, NewLogOptions(config, false, nil, LvlInfo))
134 if c.InfoHandler != nil || oldInfo != nil {
135 if c.InfoHandler == nil {
136 c.InfoHandler = oldInfo
138 c.InfoHandler = MatchAbHandler("section", "requestlog", c.InfoHandler, oldInfo)
143 // Returns a handler for the level using the output string
144 // Accept formats for output string are
145 // LogFunctionMap[value] callback function
146 // `stdout` `stderr` `full/file/path/to/location/app.log` `full/file/path/to/location/app.json`
147 func initHandlerFor(c *CompositeMultiHandler, output, basePath string, options *LogOptions) {
148 if options.Ctx != nil {
149 options.SetExtendedOptions(
150 "noColor", !options.Ctx.BoolDefault("log.colorize", true),
151 "smallDate", options.Ctx.BoolDefault("log.smallDate", true),
152 "maxSize", options.Ctx.IntDefault("log.maxsize", 1024*10),
153 "maxAge", options.Ctx.IntDefault("log.maxage", 14),
154 "maxBackups", options.Ctx.IntDefault("log.maxbackups", 14),
155 "compressBackups", !options.Ctx.BoolDefault("log.compressBackups", true),
159 output = strings.TrimSpace(output)
160 if funcHandler, found := LogFunctionMap[output]; found {
161 funcHandler(c, options)
167 // No handler, discard data
169 // Write to file specified
170 if !filepath.IsAbs(output) {
171 output = filepath.Join(basePath, output)
174 if err := os.MkdirAll(filepath.Dir(output), 0755); err != nil {
178 if strings.HasSuffix(output, "json") {
179 c.SetJsonFile(output, options)
181 // Override defaults for a terminal file
182 options.SetExtendedOptions("noColor", true)
183 options.SetExtendedOptions("smallDate", false)
184 c.SetTerminalFile(output, options)