master
Jordan Orelli 10 years ago
parent 59ed0fc7da
commit 04b8cad832

@ -45,5 +45,6 @@ func main() {
func init() { func init() {
flag.IntVar(&options.port, "port", 8000, "port to serve on") flag.IntVar(&options.port, "port", 8000, "port to serve on")
flag.StringVar(&options.hostname, "host", "", "hostname") flag.StringVar(&options.hostname, "host", "", "hostname")
log.SetOutput(os.Stdout)
log.SetFlags(log.Ldate | log.Lmicroseconds) log.SetFlags(log.Ldate | log.Lmicroseconds)
} }

@ -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
}

@ -0,0 +1,7 @@
// +build darwin dragonfly freebsd netbsd openbsd
package main
import "syscall"
const ioctlReadTermios = syscall.TIOCGETA

@ -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

@ -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)
}

@ -1,8 +1,11 @@
package main package main
import ( import (
"github.com/jordanorelli/serve/termcolors"
"log" "log"
"net/http" "net/http"
"os"
"strconv"
"time" "time"
) )
@ -12,11 +15,15 @@ type logWrapper struct {
func (l *logWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (l *logWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
id := newRequestId() id := newRequestId()
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) log.Println(id, r.Method, r.URL)
}
statsThing := &writerWatcher{ResponseWriter: w} statsThing := &writerWatcher{ResponseWriter: w}
start := time.Now() start := time.Now()
l.Handler.ServeHTTP(statsThing, r) 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 { type writerWatcher struct {
@ -38,3 +45,24 @@ func (w *writerWatcher) WriteHeader(status int) {
w.headerWritten = status w.headerWritten = status
w.ResponseWriter.WriteHeader(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)
}
}

Loading…
Cancel
Save