func (h *LogrusHandler) joinKVs(skipUnchanged bool, sep string) []string { kv := make([]string, 0, len(h.Fields)) for k, v := range h.Fields { if !h.Opts.shouldShowKey(k) { continue } if skipUnchanged { if lastV, ok := h.last[k]; ok && lastV == v { continue } } kstr := rgbterm.FgString(k, h.Opts.KeyRGB.R, h.Opts.KeyRGB.G, h.Opts.KeyRGB.B) var vstr string if h.Opts.Truncates && len(v) > h.Opts.TruncateLength { vstr = v[:h.Opts.TruncateLength] + "..." } else { vstr = v } vstr = rgbterm.FgString(vstr, h.Opts.ValRGB.R, h.Opts.ValRGB.G, h.Opts.ValRGB.B) kv = append(kv, kstr+sep+vstr) } sort.Strings(kv) if h.Opts.SortLongest { sort.Stable(byLongest(kv)) } return kv }
func ColorString(color Color, str string) string { logger.Logger.Println("BEFORE!!!", spew.Sdump(str)) c := rgbterm.FgString(str, color.R, color.G, color.B) c = strings.Replace(c, "\x1b", "\033", -1) tt := cc.New(cc.FgGreen).SprintFunc() logger.Logger.Println("AFTER!!!", spew.Sdump(c), spew.Sdump(tt("TEST"))) return c }
func main() { app := newApp() prefix := rgbterm.FgString(app.Name+"> ", 99, 99, 99) log.SetFlags(0) log.SetPrefix(prefix) err := app.Run(os.Args) if err != nil { log.Fatal(err) } }
// Prettify the output in a logrus like fashion. func (h *LogrusHandler) Prettify(skipUnchanged bool) []byte { defer h.clear() if h.out == nil { if h.Opts == nil { h.Opts = DefaultOptions } h.buf = bytes.NewBuffer(nil) h.out = tabwriter.NewWriter(h.buf, 0, 1, 0, '\t', 0) } var msg string if h.Message == "" { msg = rgbterm.FgString("<no msg>", 190, 190, 190) } else { msg = rgbterm.FgString(h.Message, 255, 255, 255) } lvl := strings.ToUpper(h.Level)[:imin(4, len(h.Level))] var level string switch h.Level { case "debug": level = rgbterm.FgString(lvl, 221, 28, 119) case "info": level = rgbterm.FgString(lvl, 20, 172, 190) case "warn", "warning": level = rgbterm.FgString(lvl, 255, 245, 32) case "error": level = rgbterm.FgString(lvl, 255, 0, 0) case "fatal", "panic": level = rgbterm.BgString(lvl, 255, 0, 0) default: level = rgbterm.FgString(lvl, 221, 28, 119) } _, _ = fmt.Fprintf(h.out, "%s |%s| %s\t %s", rgbterm.FgString(h.Time.Format(time.Stamp), 99, 99, 99), level, msg, strings.Join(h.joinKVs(skipUnchanged, "="), "\t "), ) _ = h.out.Flush() return h.buf.Bytes() }
func ColorStringF(color Color, format string, args ...interface{}) string { return rgbterm.FgString(fmt.Sprintf(format, args), color.R, color.G, color.B) }
func (ss *terminalSink) Error(message string) { messageTime := time.Now().Format(time.RFC3339) leveledMessage := fmt.Sprintf("[ERROR ] %s %s", messageTime, message) colouredMessage := rgbterm.FgString(leveledMessage, 220, 50, 47) fmt.Println(colouredMessage) }
func (ss *terminalSink) Debug(message string) { messageTime := time.Now().Format(time.RFC3339) leveledMessage := fmt.Sprintf("[DEBUG ] %s %s", messageTime, message) colouredMessage := rgbterm.FgString(leveledMessage, 42, 161, 152) fmt.Println(colouredMessage) }
func (ss *terminalSink) Warning(message string) { messageTime := time.Now().Format(time.RFC3339) leveledMessage := fmt.Sprintf("[WARNING] %s %s", messageTime, message) colouredMessage := rgbterm.FgString(leveledMessage, 181, 137, 0) fmt.Println(colouredMessage) }
// Fprint is used by all of the logging functions to send output to the output // stream. // // flags sets the output flags to use when writing the output. // // logLevel is the level of the output. // // calldepth is the number of stack frames to skip when getting the file // name of original calling function for file name output. // // text is the string to append to the assembled log format output. If the text // is prefixed with newlines, they will be stripped out and placed in front of // the completed output (test with template applied) before writing it to the // stream. // // stream will be used as the output stream the text will be written to. If // stream is nil, the stream value contained in the logger object is used. // // Fprint returns the number of bytes written to the stream or an error. func (l *Logger) Fprint(flags int, logLevel level, calldepth int, text string, stream io.Writer) (n int, err error) { if (logLevel != LEVEL_PRINT && l.level != LEVEL_PRINT) && logLevel < l.level { return } // Check for string excludes if len(l.excludeStrings) > 0 { for _, val := range l.excludeStrings { if strings.Contains(text, val) { return } } } now := time.Now() var pgmC uintptr var file, fName string var line int var id string var indentCount int l.mu.Lock() defer l.mu.Unlock() if flags&(LlongFileName|LshortFileName|LfunctionName) != 0 || len(l.excludeFuncNames) > 0 { // release lock while getting caller info - it's expensive. // l.mu.Unlock() pgmC, file, line, _ = runtime.Caller(calldepth) if flags&LshortFileName != 0 { short := file for i := len(file) - 1; i > 0; i-- { if file[i] == '/' { short = file[i+1:] break } } file = short } if flags&LfunctionName != 0 || len(l.excludeFuncNames) > 0 { fAtPC := runtime.FuncForPC(pgmC) fName = fAtPC.Name() for i := len(fName) - 1; i >= 0; i-- { if fName[i] == '.' { fName = fName[i+1:] break } } } // l.mu.Lock() } // Check func name excludes and return if matches are found if len(fName) > 0 { for _, name := range l.excludeFuncNames { if strings.Contains(fName, name) { return } } } l.buf = l.buf[:0] // Reset! trimText := strings.TrimLeft(text, "\t\v\r\n") trimedCount := len(text) - len(trimText) if trimedCount > 0 { l.buf = append(l.buf, trimText...) } else { l.buf = append(l.buf, text...) } var date string var seperator string if flags&Ldate != 0 { date = now.Format(l.dateFormat) } if flags&Lseperator != 0 { seperator = l.seperator } if flags&LlineNumber == 0 { line = 0 } if flags&(LshortFileName|LlongFileName) == 0 { file = "" } if flags&LfunctionName == 0 { fName = "" } var indent string if indentCount > 0 || flags&Lindent != 0 { for i := 0; i < indentCount+l.indent; i++ { for j := 0; j < l.tabStop; j++ { if flags&LshowIndent != 0 && j == 0 { indent += "|" } else if flags&LshowIndent != 0 { indent += "." } else { indent += " " } } } if len(indent) > 0 && string(indent[0]) != " " { indent = rgbterm.FgString(indent, defaultIndentColor[0], defaultIndentColor[1], defaultIndentColor[2]) } } var label string if flags&Llabel != 0 { if flags&Lcolor != 0 { label = logLevel.AnsiLabel() } else { label = logLevel.Label() } } f := &format{ Seperator: seperator, LogLabel: label, Date: date, FileName: file, FunctionName: fName, LineNumber: line, Indent: indent, Id: id, Text: string(l.buf), } var out bytes.Buffer var strippedText, finalText string err = l.template.Execute(&out, f) if err != nil { panic(err) } if flags&Lcolor == 0 { strippedText = stripAnsi(out.String()) } if trimedCount > 0 && flags&Lcolor == 0 { finalText = text[:trimedCount] + strippedText } else if trimedCount > 0 && flags&Lcolor != 0 { finalText = text[:trimedCount] + out.String() } else if flags&Lcolor == 0 { finalText = strippedText } else { finalText = out.String() } if stream == nil { n, err = l.Write([]byte(finalText)) } else { n, err = stream.Write([]byte(finalText)) } return }
// Colorized returns the colorized label for console output using ANSI escape // sequences. func (l Label) Colorized() string { if l.level == LEVEL_PRINT { return l.name } return rgbterm.FgString(l.name, l.colorRGB[0], l.colorRGB[1], l.colorRGB[2]) }
// at all. LEVEL_ERROR // LEVEL_CRITICAL messages are used when something is completely broken // and unrecoverable. Critical messages are usually followed by // os.Exit(). LEVEL_CRITICAL // LEVEL_PRINT shows output for the standard Print functions and above. LEVEL_PRINT ) var ( defaultDate = time.RFC3339 defaultSeperator = "::" defaultSeperatorColor = rgbterm.FgString("::", 0, 255, 135) // Green defaultIndentColor = []uint8{0, 135, 175} // Grayish blue ) // Flags are used to control the formatting of the logging output. const ( // These flags define which text to prefix to each log entry generated // by the Logger. Bits or'ed together to control what's printed. Ldate = 1 << iota // Full file name and line number: /a/b/c/d.go:23 LlongFileName // Base file name and line number: d.go:23. overrides LshortFileName LshortFileName
var date = "Mon 20060102 15:04:05" var fprintOutputTests = []struct { template string seperator string level level dateFormat string flags int text string expect string expectErr bool }{ // Test with color seperator { template: logFmt, seperator: rgbterm.FgString("TEST>", 0, 255, 0), level: LEVEL_PRINT, dateFormat: date, flags: LstdFlags, text: "test number 1", // The %s format specifier is the placeholder for the date. expect: "%s \x1b[38;5;46mTEST>\x1b[0;00m test number 1", expectErr: false, }, // Test output with coloring turned off { template: logFmt, seperator: "TEST>", level: LEVEL_PRINT, dateFormat: date, flags: Ldate | Lseperator,
// This code is MIT licensed. See the LICENSE file for more info. package logs import ( "fmt" "testing" "github.com/aybabtme/rgbterm" ) var colorTests = []struct { escapeCodes string output string }{ {rgbterm.FgString("red foreground color", 255, 0, 0), "\x1b[38;5;196mred foreground color\x1b[0;00m"}, {rgbterm.FgString("green foreground color", 0, 255, 0), "\x1b[38;5;46mgreen foreground color\x1b[0;00m"}, {rgbterm.FgString("blue foreground color", 0, 0, 255), "\x1b[38;5;21mblue foreground color\x1b[0;00m"}, } func TestColors(t *testing.T) { for i, v := range colorTests { if out := v.escapeCodes; out != v.output { fmt.Println(v.escapeCodes) t.Errorf("Test Number: %d\nGot:\t%q\nExpect:\t%q\n", i, v.escapeCodes, v.output) } }