package logger import ( "encoding/json" "fmt" "log" "os" "runtime" "strconv" "strings" "time" "finclip-app-manager/infrastructure/config" "github.com/Shopify/sarama" ) var logProducer sarama.AsyncProducer type LogContent struct { LogName string `json:"logger_name"` LogLevel string `json:"loglevel"` Message string `json:"message"` Class string `json:"class"` Host string `json:"host"` File string `json:"file"` Method string `json:"method"` LineNumber string `json:"line_number"` ThreadName string `json:"thread_name"` AppName string `json:"Appname"` ProjectName string `json:"projectname"` Timestamp string `json:"timestamp"` } func init() { if config.GetConfig().OpenKafkaLog { kafkaConfig := sarama.NewConfig() kafkaConfig.Producer.RequiredAcks = sarama.WaitForLocal kafkaConfig.Producer.Compression = sarama.CompressionSnappy kafkaConfig.Producer.Flush.Frequency = 500 * time.Millisecond var err error addrs := strings.Split(config.GetConfig().KafkaAddr, ",") logProducer, err = sarama.NewAsyncProducer(addrs, kafkaConfig) if err != nil { panic(err) } fmt.Println("log kafka init succ ...") } } func getLogInfo() (string, string, string) { _, file, line, ok := runtime.Caller(3) if !ok { file = "???" line = 0 } else { short := file for i := len(file) - 1; i > 0; i-- { if file[i] == '/' { short = file[i+1:] break } } file = short } pc := make([]uintptr, 1) runtime.Callers(4, pc) f := runtime.FuncForPC(pc[0]) return file, f.Name(), strconv.Itoa(line) } func getLogUtcTime() string { t := time.Now().Format("2006-01-02 15:04:05") loc, _ := time.ParseInLocation("2006-01-02 15:04:05", t, time.Local) return loc.UTC().Format("2006-01-02T15:04:05.000Z") } func pullLogToKafka(logStr, logLevel string) error { if config.GetConfig().OpenKafkaLog { file, function, line := getLogInfo() content := LogContent{} content.LogName = config.GetConfig().ServerName + ".log" content.LogLevel = logLevel content.Message = logStr content.Class = "test_class" content.Host = "127.0.0.1" content.File = file content.Method = function content.LineNumber = line content.ThreadName = "test_thread_name" content.AppName = config.GetConfig().ServerName content.ProjectName = config.GetConfig().ServerName content.Timestamp = getLogUtcTime() valueByte, _ := json.Marshal(content) logProducer.Input() <- &sarama.ProducerMessage{ Topic: config.GetConfig().LogTopic, Value: sarama.ByteEncoder(string(valueByte)), } } return nil } // Logger is the server logger type Logger struct { logger *log.Logger debug bool trace bool file bool infoLabel string errorLabel string fatalLabel string debugLabel string traceLabel string } // NewStdLogger creates a logger with output directed to Stderr func NewStdLogger(time, file, debug, trace, colors, pid bool) *Logger { flags := 0 if time { flags = log.LstdFlags | log.Lmicroseconds } pre := "" if pid { pre = pidPrefix() } l := &Logger{ logger: log.New(os.Stdout, pre, flags), debug: debug, trace: trace, file: file, } if colors { setColoredLabelFormats(l) } else { setPlainLabelFormats(l) } return l } // NewFileLogger creates a logger with output directed to a file func NewFileLogger(filename string, time, file, debug, trace, pid bool) *Logger { fileflags := os.O_WRONLY | os.O_APPEND | os.O_CREATE f, err := os.OpenFile(filename, fileflags, 0660) if err != nil { log.Fatalf("error opening file: %v", err) } flags := 0 if time { flags = log.LstdFlags | log.Lmicroseconds } pre := "" if pid { pre = pidPrefix() } l := &Logger{ logger: log.New(f, pre, flags), debug: debug, trace: trace, file: file, } setPlainLabelFormats(l) return l } // Generate the pid prefix string func pidPrefix() string { return fmt.Sprintf("[%d] ", os.Getpid()) } func setPlainLabelFormats(l *Logger) { l.infoLabel = "[INF]" l.debugLabel = "[DBG]" l.errorLabel = "[ERR]" l.fatalLabel = "[FTL]" l.traceLabel = "[TRC]" } func setColoredLabelFormats(l *Logger) { colorFormat := "[\x1b[%dm%s\x1b[0m]" l.infoLabel = fmt.Sprintf(colorFormat, 32, "INF") l.debugLabel = fmt.Sprintf(colorFormat, 36, "DBG") l.errorLabel = fmt.Sprintf(colorFormat, 31, "ERR") l.fatalLabel = fmt.Sprintf(colorFormat, 31, "FTL") l.traceLabel = fmt.Sprintf(colorFormat, 33, "TRC") } // copy from go/src/log/log.go and modify by guojuntao, 2017/09/21 // Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding. func itoa(i int, wid int) string { // Assemble decimal in reverse order. var b [20]byte bp := len(b) - 1 for i >= 10 || wid > 1 { wid-- q := i / 10 b[bp] = byte('0' + i - q*10) bp-- i = q } // i < 10 b[bp] = byte('0' + i) return string(b[bp:]) } func (l *Logger) getFileLineFormat(calldepth int) string { if l.file { _, file, line, ok := runtime.Caller(calldepth) if !ok { file = "???" line = 0 } short := file for i := len(file) - 1; i > 0; i-- { if file[i] == '/' { short = file[i+1:] break } } file = short return " " + file + ":" + itoa(line, -1) + ":" } return "" } // Noticef logs a notice statement func (l *Logger) Noticef(format string, v ...interface{}) { pullLogToKafka(fmt.Sprintf(format, v...), "NOTICE") l.logger.Printf(l.infoLabel+l.getFileLineFormat(2)+" "+format, v...) } func (l *Logger) Noticeln(v ...interface{}) { pullLogToKafka(fmt.Sprint(v...), "NOTICE") l.logger.Println(append([]interface{}{l.infoLabel + l.getFileLineFormat(2)}, v...)...) } // Warf logs an error statement func (l *Logger) Warf(format string, v ...interface{}) { pullLogToKafka(fmt.Sprintf(format, v...), "WARNING") l.logger.Printf(l.errorLabel+l.getFileLineFormat(2)+" "+format, v...) } // Errorf logs an error statement func (l *Logger) Errorf(format string, v ...interface{}) { pullLogToKafka(fmt.Sprintf(format, v...), "ERROR") l.logger.Printf(l.errorLabel+l.getFileLineFormat(2)+" "+format, v...) } func (l *Logger) Errorln(v ...interface{}) { pullLogToKafka(fmt.Sprint(v...), "ERROR") l.logger.Println(append([]interface{}{l.errorLabel + l.getFileLineFormat(2)}, v...)...) } // Fatalf logs a fatal error func (l *Logger) Fatalf(format string, v ...interface{}) { pullLogToKafka(fmt.Sprintf(format, v...), "FATAL") l.logger.Fatalf(l.fatalLabel+l.getFileLineFormat(2)+" "+format, v...) } func (l *Logger) Fatalln(v ...interface{}) { pullLogToKafka(fmt.Sprint(v...), "FATAL") l.logger.Fatalln(append([]interface{}{l.fatalLabel + l.getFileLineFormat(2)}, v...)...) } // Debugf logs a debug statement func (l *Logger) Debugf(format string, v ...interface{}) { if l.debug { pullLogToKafka(fmt.Sprintf(format, v...), "DEBUG") l.logger.Printf(l.debugLabel+l.getFileLineFormat(2)+" "+format, v...) } } func (l *Logger) Debugln(v ...interface{}) { if l.debug { pullLogToKafka(fmt.Sprint(v...), "DEBUG") l.logger.Println(append([]interface{}{l.debugLabel + l.getFileLineFormat(2)}, v...)...) } } // Infof logs a debug statement func (l *Logger) Infof(format string, v ...interface{}) { if l.debug { pullLogToKafka(fmt.Sprintf(format, v...), "INFO") l.logger.Printf(l.debugLabel+l.getFileLineFormat(2)+" "+format, v...) } } func (l *Logger) Infoln(v ...interface{}) { if l.debug { pullLogToKafka(fmt.Sprint(v...), "INFO") l.logger.Println(append([]interface{}{l.debugLabel + l.getFileLineFormat(2)}, v...)...) } } // Tracef logs a trace statement func (l *Logger) Tracef(format string, v ...interface{}) { if l.trace { pullLogToKafka(fmt.Sprintf(format, v...), "TRACE") l.logger.Printf(l.traceLabel+l.getFileLineFormat(2)+" "+format, v...) } } func (l *Logger) Traceln(v ...interface{}) { if l.trace { pullLogToKafka(fmt.Sprint(v...), "TRACE") l.logger.Println(append([]interface{}{l.traceLabel + l.getFileLineFormat(2)}, v...)...) } } func (l *Logger) IsDebugEnabled() bool { return l.debug } func (l *Logger) IsTraceEnabled() bool { return l.trace }