Add API Framework Revel Source Files
[iec.git] / src / foundation / api / revel / logger / init.go
1 package logger
2
3 // Get all handlers based on the Config (if available)
4 import (
5         "fmt"
6         "github.com/revel/config"
7         "log"
8         "os"
9         "path/filepath"
10         "strings"
11 )
12
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")
22         }
23
24         // If the configuration has an all option we can skip some
25         c, _ = NewCompositeMultiHandler()
26
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)
30         }
31         initLogLevels(c, basePath, config)
32         if c.CriticalHandler == nil && c.ErrorHandler != nil {
33                 c.CriticalHandler = c.ErrorHandler
34         }
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
39                 }
40                 initRequestLog(c, basePath, config)
41         }
42
43         return c
44 }
45
46 // Init the log.all configuration options
47 func initAllLog(c *CompositeMultiHandler, basePath string, config *config.Context) {
48         if config != nil {
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
52                         if extraLogFlag {
53                                 log.Printf("Adding standard handler for levels to >%s< ", output)
54                         }
55                         initHandlerFor(c, output, basePath, NewLogOptions(config, true, nil, LvlAllList...))
56                 }
57         }
58 }
59
60 // Init the filter options
61 // log.all.filter ....
62 // log.error.filter ....
63 func initFilterLog(c *CompositeMultiHandler, basePath string, config *config.Context) {
64
65         if config != nil {
66                 extraLogFlag := config.BoolDefault(SPECIAL_USE_FLAG, false)
67
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
72                         } {
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]
79                                         }
80                                         phandler := logFilter.parentHandler(keyMap)
81                                         if extraLogFlag {
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)
84                                         }
85
86                                         if name == "all" {
87                                                 initHandlerFor(c, config.StringDefault(option, ""), basePath, NewLogOptions(config, false, phandler))
88                                         } else {
89                                                 initHandlerFor(c, config.StringDefault(option, ""), basePath, NewLogOptions(config, false, phandler, toLevel[name]))
90                                         }
91                                 }
92                         }
93                 }
94         }
95 }
96
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
101         } {
102                 if config != nil {
103                         extraLogFlag := config.BoolDefault(SPECIAL_USE_FLAG, false)
104                         output, found := config.String("log." + name + ".output")
105                         if found {
106                                 if extraLogFlag {
107                                         log.Printf("Adding standard handler %s output %s", name, output)
108                                 }
109                                 initHandlerFor(c, output, basePath, NewLogOptions(config, true, nil, toLevel[name]))
110                         }
111                         // Gets the list of options with said prefix
112                 } else {
113                         initHandlerFor(c, "stderr", basePath, NewLogOptions(config, true, nil, toLevel[name]))
114                 }
115         }
116 }
117
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"
126         if config != nil {
127                 outputRequest = config.StringDefault("log.request.output", "")
128         }
129         oldInfo := c.InfoHandler
130         c.InfoHandler = nil
131         if outputRequest != "" {
132                 initHandlerFor(c, outputRequest, basePath, NewLogOptions(config, false, nil, LvlInfo))
133         }
134         if c.InfoHandler != nil || oldInfo != nil {
135                 if c.InfoHandler == nil {
136                         c.InfoHandler = oldInfo
137                 } else {
138                         c.InfoHandler = MatchAbHandler("section", "requestlog", c.InfoHandler, oldInfo)
139                 }
140         }
141 }
142
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),
156                 )
157         }
158
159         output = strings.TrimSpace(output)
160         if funcHandler, found := LogFunctionMap[output]; found {
161                 funcHandler(c, options)
162         } else {
163                 switch output {
164                 case "":
165                         fallthrough
166                 case "off":
167                 // No handler, discard data
168                 default:
169                         // Write to file specified
170                         if !filepath.IsAbs(output) {
171                                 output = filepath.Join(basePath, output)
172                         }
173
174                         if err := os.MkdirAll(filepath.Dir(output), 0755); err != nil {
175                                 log.Panic(err)
176                         }
177
178                         if strings.HasSuffix(output, "json") {
179                                 c.SetJsonFile(output, options)
180                         } else {
181                                 // Override defaults for a terminal file
182                                 options.SetExtendedOptions("noColor", true)
183                                 options.SetExtendedOptions("smallDate", false)
184                                 c.SetTerminalFile(output, options)
185                         }
186                 }
187         }
188         return
189 }