github.com/jbking/gohan@v0.0.0-20151217002006-b41ccf1c2a96/log/log.go (about) 1 // Copyright (C) 2015 NTT Innovation Institute, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 // implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 package log 17 18 import ( 19 "encoding/json" 20 "fmt" 21 "io" 22 "os" 23 "runtime" 24 "strings" 25 26 logging "github.com/op/go-logging" 27 28 "github.com/cloudwan/gohan/util" 29 ) 30 31 var defaultLoggerName = "unknown" 32 var defaultLogLevel = logging.INFO.String() 33 34 func mustGohanJSONFormatter(componentName string) *gohanJSONFormatter { 35 return &gohanJSONFormatter{componentName: componentName} 36 } 37 38 type gohanJSONFormatter struct { 39 componentName string 40 } 41 42 // GetModuleName returns module name 43 func GetModuleName() string { 44 pc, _, _, ok := runtime.Caller(1) 45 if !ok { 46 return defaultLoggerName 47 } 48 f := runtime.FuncForPC(pc) 49 if f == nil { 50 return defaultLoggerName 51 } 52 // componentName will be equal to something like: 53 // dir_to_gohan/gohan/some_dirs/package_name/(*class_name).func_name 54 componentName := f.Name() 55 componentName = strings.Replace(componentName, "/", ".", -1) 56 nameStart := strings.Index(componentName, "gohan.") 57 nameStop := strings.LastIndex(componentName, "(") - 1 58 if nameStop < 0 { 59 nameStop = strings.LastIndex(componentName, ".") 60 if nameStop < 0 { 61 nameStop = len(componentName) 62 } 63 } 64 if nameStart < 0 { 65 nameStart = 0 66 } 67 return componentName[nameStart:nameStop] 68 } 69 70 //Format formats message to JSON format 71 func (f *gohanJSONFormatter) Format(calldepth int, record *logging.Record, output io.Writer) error { 72 result := map[string]interface{}{ 73 "timestamp": record.Time, 74 "log_level": record.Level.String(), 75 "log_type": "log", 76 "msg": record.Message(), 77 "component_name": record.Module, 78 } 79 resultJSON, err := json.Marshal(result) 80 if err != nil { 81 return err 82 } 83 fmt.Fprintf(output, "%s\n", resultJSON) 84 return nil 85 } 86 87 //SetUpLogging configures logging based on configuration 88 func SetUpLogging(config *util.Config) error { 89 var backends = []logging.Backend{} 90 91 if prefix := "logging/file/"; config.GetBool(prefix+"enabled", false) { 92 logFile, err := os.OpenFile(config.GetString(prefix+"filename", "gohan.log"), 93 os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660) 94 if err != nil { 95 return err 96 } 97 fileBackendLeveled := getLeveledBackend(logFile, mustGohanJSONFormatter("gohan")) 98 addLevelsToBackend(config, prefix, fileBackendLeveled) 99 backends = append(backends, fileBackendLeveled) 100 } 101 102 if prefix := "logging/stderr/"; config.GetBool(prefix+"enabled", true) { 103 stringFormatter := logging.MustStringFormatter( 104 "%{color}%{time:15:04:05.000} %{module} %{level} %{color:reset} %{message}", 105 ) 106 stderrBackendLeveled := getLeveledBackend(os.Stderr, stringFormatter) 107 addLevelsToBackend(config, prefix, stderrBackendLeveled) 108 backends = append(backends, stderrBackendLeveled) 109 } 110 111 logging.SetBackend(backends...) 112 return nil 113 } 114 115 func getLeveledBackend(out io.Writer, formatter logging.Formatter) logging.LeveledBackend { 116 backend := logging.NewLogBackend(out, "", 0) 117 backendFormatter := logging.NewBackendFormatter(backend, formatter) 118 return logging.AddModuleLevel(backendFormatter) 119 } 120 121 func addLevelsToBackend(config *util.Config, prefix string, backend logging.LeveledBackend) { 122 level, _ := logging.LogLevel(config.GetString(prefix+"level", defaultLogLevel)) 123 backend.SetLevel(level, "") 124 modules := config.GetList(prefix+"modules", []interface{}{}) 125 for _, rawModule := range modules { 126 module, _ := rawModule.(map[string]interface{}) 127 moduleName, _ := module["name"].(string) 128 moduleLevel, _ := module["level"].(string) 129 level, err := logging.LogLevel(moduleLevel) 130 if moduleName == "" || err != nil { 131 continue 132 } 133 backend.SetLevel(level, moduleName) 134 } 135 }