package logger import ( "encoding/json" "fmt" "io" "strings" "time" "gitlab.com/uafrica/go-utils/errors" ) type ILogger interface { Fatalf(format string, args ...interface{}) Fatal(args ...interface{}) Errorf(format string, args ...interface{}) Error(args ...interface{}) Warnf(format string, args ...interface{}) Warn(args ...interface{}) Infof(format string, args ...interface{}) Info(args ...interface{}) Debugf(format string, args ...interface{}) Debug(args ...interface{}) } type Logger struct { //apiRequest *events.APIGatewayProxyRequest //currentRequestID *string level Level writer io.Writer data map[string]interface{} } func (l Logger) WithFields(data map[string]interface{}) Logger { newLogger := Logger{ level: l.level, writer: l.writer, data: map[string]interface{}{}, } for n, v := range l.data { newLogger.data[n] = v } for n, v := range data { newLogger.data[n] = v } return newLogger } func (l Logger) Fatalf(format string, args ...interface{}) { l.WithFields(map[string]interface{}{"call_stack": errors.Stack(3)}).log(LevelFatal, 1, fmt.Sprintf(format, args...)) } func (l Logger) Fatal(args ...interface{}) { l.WithFields(map[string]interface{}{"call_stack": errors.Stack(3)}).log(LevelFatal, 1, fmt.Sprint(args...)) } func (l Logger) Errorf(format string, args ...interface{}) { l.WithFields(map[string]interface{}{"call_stack": errors.Stack(3)}).log(LevelError, 1, fmt.Sprintf(format, args...)) } func (l Logger) Error(args ...interface{}) { l.WithFields(map[string]interface{}{"call_stack": errors.Stack(3)}).log(LevelError, 1, fmt.Sprint(args...)) } func (l Logger) Warnf(format string, args ...interface{}) { l.log(LevelError, 1, fmt.Sprintf(format, args...)) } func (l Logger) Warn(args ...interface{}) { l.log(LevelError, 1, fmt.Sprint(args...)) } func (l Logger) Infof(format string, args ...interface{}) { l.log(LevelInfo, 1, fmt.Sprintf(format, args...)) } func (l Logger) Info(args ...interface{}) { l.log(LevelInfo, 1, fmt.Sprint(args...)) } func (l Logger) Debugf(format string, args ...interface{}) { l.log(LevelDebug, 1, fmt.Sprintf(format, args...)) } func (l Logger) Debug(args ...interface{}) { l.log(LevelDebug, 1, fmt.Sprint(args...)) } func (l Logger) log(level Level, skip int, msg string) { if level <= l.level && l.writer != nil { entry := Entry{ Timestamp: time.Now(), Level: level, Caller: errors.GetCaller(skip + 2).Info(), Data: l.data, Message: strings.ReplaceAll(msg, "\n", ";"), } // jsonEntry, err := json.Marshal(entry) // if err != nil { // l.writer.Write([]byte(fmt.Sprintf("failed to marshal entry: %v: %+v\n", err, entry))) // } // l.writer.Write(append(jsonEntry, []byte("\n")...)) source := fmt.Sprintf("%s(%d)", entry.Caller.File, entry.Caller.Line) if len(source) > 25 { source = source[len(source)-25:] } textEntry := fmt.Sprintf("%s %5.5s %-25.25s %s", entry.Timestamp.Format("2006-01-02 15:04:05"), entry.Level, source, entry.Message) if len(entry.Data) > 0 { jsonData, _ := json.Marshal(entry.Data) textEntry += " " + string(jsonData) } l.writer.Write(append([]byte(textEntry), []byte("\n")...)) } } type Entry struct { Timestamp time.Time `json:"time"` Level Level `json:"level"` Caller errors.CallerInfo `json:"caller"` Data map[string]interface{} `json:"data"` Message string `json:"message"` } // func sendRaygunError(fields map[string]interface{}, errToSend error) { // if os.Getenv("DEBUGGING") == "true" { // // Don't log raygun errors on debug // return // } // raygun, err := RaygunReporter() // if err != nil || raygun == nil { // logger.Errorf("Unable to create Raygun client: " + err.Error()) // return // } // env := getEnvironment() // tags := []string{env} // //todo: raygun.Version(globals.BuildVersion) // //todo: tags = append(tags, globals.BuildVersion) // if logger.apiRequest != nil { // methodAndPath := logger.apiRequest.HTTPMethod + ": " + logger.apiRequest.Path // tags = append(tags, methodAndPath) // fields["body"] = logger.apiRequest.Body // fields["query"] = logger.apiRequest.QueryStringParameters // fields["identity"] = logger.apiRequest.RequestContext.Identity // } // raygun.Tags(tags) // if logger.currentRequestID != nil { // fields["request_id"] = logger.currentRequestID // } // fields["env"] = env // raygun.CustomData(fields) // raygun.Request(fakeHttpRequest()) // if errToSend == nil { // errToSend = errors.New("") // } // err = raygun.SendError(errToSend) // if err != nil { // logger.Errorf("Failed to send raygun error: " + err.Error()) // } // } // func fakeHttpRequest() *http.Request { // if logger.apiRequest == nil { // return nil // } // requestURL := url.URL{ // Path: logger.apiRequest.Path, // Host: logger.apiRequest.Headers["Host"], // } // request := http.Request{ // Method: logger.apiRequest.HTTPMethod, // URL: &requestURL, // Header: logger.apiRequest.MultiValueHeaders, // } // return &request // } // func RaygunReporter() (*raygun4go.Client, error) { // key := "AwdpHhwOF1lTT6AppyEHA" // // TODO Raygun per environment // //env := getEnvironment() // //if env == "dev" { // // key = "q98iTyE5CcF7raZsIiLA" // //} else if env == "stage" { // // key = "TA54mzcv9cBWBLmfwIQMDg" // //} else if env == "prod" { // // key = "BXdraqiPKBXImqP4siK1w" // //} // raygun, err := raygun4go.New("uAfrica V3", key) // if err != nil || raygun == nil { // logger.Errorf("Unable to create Raygun client:" + err.Error()) // return nil, err // } // return raygun, nil // }