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  }