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