package masterlog import ( "encoding/json" "fmt" "time" ) // getShortFile extracts the filename from a full path func getShortFile(file string) string { for i := len(file) - 1; i >= 0; i-- { if file[i] == '/' { return file[i+1:] } } return file } // FormattedEncoder encodes entries in the formatted text format type FormattedEncoder struct { useColors bool } // NewFormattedEncoder creates a new FormattedEncoder func NewFormattedEncoder(useColors bool) *FormattedEncoder { return &FormattedEncoder{useColors: useColors} } func (e *FormattedEncoder) Encode(entry Entry) ([]byte, error) { // Format: 2022-09-01T10:05:03+01:00 TRC main.go:23 trace message go_version=go1.19 pid=2620043 format := entry.Timestamp.Format(time.RFC3339) levelStr := levelNames[entry.Level] shortFile := getShortFile(entry.File) var result string if e.useColors { // Timestamp in light gray timestampColor := colorLightGray // Level in its specific color levelColor := levelColors[entry.Level] // File:line in light gray fileColor := colorLightGray // Separator in light gray separator := ">" // Message in white messageColor := colorWhite result = fmt.Sprintf("%s%s%s %s%s%s %s%s%s:%d %s%s%s %s%s%s", timestampColor, format, colorReset, levelColor, levelStr, colorReset, fileColor, shortFile, colorReset, entry.Line, fileColor, separator, colorReset, messageColor, entry.Message, colorReset) } else { result = fmt.Sprintf("%s %s %s:%d > %s", format, levelStr, shortFile, entry.Line, entry.Message) } // Add fields - first custom fields, then default fields // Custom fields (user-provided) for key, value := range entry.CustomFields { if e.useColors { // Field key in turquoise, value in white result += fmt.Sprintf(" %s%s%s=%s%v%s", colorTurquoise, key, colorReset, colorWhite, value, colorReset) } else { result += fmt.Sprintf(" %s=%v", key, value) } } // Default fields (go_version, pid) for key, value := range entry.DefaultFields { if e.useColors { // Field key in turquoise, value in white result += fmt.Sprintf(" %s%s%s=%s%v%s", colorTurquoise, key, colorReset, colorWhite, value, colorReset) } else { result += fmt.Sprintf(" %s=%v", key, value) } } result += "\n" return []byte(result), nil } // JSONEncoder encodes entries in JSON format type JSONEncoder struct{} func (e *JSONEncoder) Encode(entry Entry) ([]byte, error) { type LogEntry struct { Timestamp string `json:"timestamp"` Level string `json:"level"` File string `json:"file"` Line int `json:"line"` Message string `json:"message"` Fields map[string]interface{} `json:"fields,omitempty"` } logEntry := LogEntry{ Timestamp: entry.Timestamp.Format(time.RFC3339), Level: levelNames[entry.Level], File: getShortFile(entry.File), Line: entry.Line, Message: entry.Message, Fields: entry.Fields, } return json.Marshal(logEntry) }