From 04b8cad83201b78f83c4a2dcf2a5064490c68738 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Sat, 1 Nov 2014 19:48:47 -0400 Subject: [PATCH] colors! --- main.go | 1 + term.go | 13 +++++++++++++ term_bsd.go | 7 +++++++ term_linux.go | 6 ++++++ termcolors/colors.go | 22 ++++++++++++++++++++++ wrappers.go | 32 ++++++++++++++++++++++++++++++-- 6 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 term.go create mode 100644 term_bsd.go create mode 100644 term_linux.go create mode 100644 termcolors/colors.go diff --git a/main.go b/main.go index e8025e5..eb0c485 100644 --- a/main.go +++ b/main.go @@ -45,5 +45,6 @@ func main() { func init() { flag.IntVar(&options.port, "port", 8000, "port to serve on") flag.StringVar(&options.hostname, "host", "", "hostname") + log.SetOutput(os.Stdout) log.SetFlags(log.Ldate | log.Lmicroseconds) } diff --git a/term.go b/term.go new file mode 100644 index 0000000..7efc353 --- /dev/null +++ b/term.go @@ -0,0 +1,13 @@ +package main + +import ( + "syscall" + "unsafe" +) + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal(fd uintptr) bool { + var termios syscall.Termios + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 +} diff --git a/term_bsd.go b/term_bsd.go new file mode 100644 index 0000000..a74562b --- /dev/null +++ b/term_bsd.go @@ -0,0 +1,7 @@ +// +build darwin dragonfly freebsd netbsd openbsd + +package main + +import "syscall" + +const ioctlReadTermios = syscall.TIOCGETA diff --git a/term_linux.go b/term_linux.go new file mode 100644 index 0000000..5d2b6aa --- /dev/null +++ b/term_linux.go @@ -0,0 +1,6 @@ +package terminal + +// These constants are declared here, rather than importing +// them from the syscall package as some syscall packages, even +// on linux, for example gccgo, do not declare them. +const ioctlReadTermios = 0x5401 // syscall.TCGETS diff --git a/termcolors/colors.go b/termcolors/colors.go new file mode 100644 index 0000000..754caf5 --- /dev/null +++ b/termcolors/colors.go @@ -0,0 +1,22 @@ +package termcolors + +type Color []byte + +const keyEscape = 27 + +var ( + Black = Color{keyEscape, '[', '3', '0', 'm'} + Red = Color{keyEscape, '[', '3', '1', 'm'} + Green = Color{keyEscape, '[', '3', '2', 'm'} + Yellow = Color{keyEscape, '[', '3', '3', 'm'} + Blue = Color{keyEscape, '[', '3', '4', 'm'} + Magenta = Color{keyEscape, '[', '3', '5', 'm'} + Cyan = Color{keyEscape, '[', '3', '6', 'm'} + White = Color{keyEscape, '[', '3', '7', 'm'} + Reset = Color{keyEscape, '[', '0', 'm'} +) + +// not efficient. +func WrapString(c Color, s string) string { + return string(c) + s + string(Reset) +} diff --git a/wrappers.go b/wrappers.go index 1442458..2a67c33 100644 --- a/wrappers.go +++ b/wrappers.go @@ -1,8 +1,11 @@ package main import ( + "github.com/jordanorelli/serve/termcolors" "log" "net/http" + "os" + "strconv" "time" ) @@ -12,11 +15,15 @@ type logWrapper struct { func (l *logWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) { id := newRequestId() - log.Println(id, r.Method, r.URL) + if IsTerminal(os.Stdout.Fd()) { + log.Println(termcolors.WrapString(termcolors.Magenta, id.String()), r.Method, r.URL) + } else { + log.Println(id, r.Method, r.URL) + } statsThing := &writerWatcher{ResponseWriter: w} start := time.Now() l.Handler.ServeHTTP(statsThing, r) - log.Println(id, statsThing.headerWritten, statsThing.written, time.Since(start)) + log.Println(id, statsThing.PrettyStatus(), statsThing.written, time.Since(start)) } type writerWatcher struct { @@ -38,3 +45,24 @@ func (w *writerWatcher) WriteHeader(status int) { w.headerWritten = status w.ResponseWriter.WriteHeader(status) } + +func (w *writerWatcher) PrettyStatus() string { + s := strconv.Itoa(w.headerWritten) + if !IsTerminal(os.Stdout.Fd()) { + return s + } + switch { + case w.headerWritten < 100: + panic("wtf") + case w.headerWritten < 200: + return termcolors.WrapString(termcolors.White, s) + case w.headerWritten < 300: + return termcolors.WrapString(termcolors.Green, s) + case w.headerWritten < 400: + return termcolors.WrapString(termcolors.White, s) + case w.headerWritten < 500: + return termcolors.WrapString(termcolors.Yellow, s) + default: + return termcolors.WrapString(termcolors.Red, s) + } +}