# HG changeset patch # User Henry Precheur # Date 1378517600 25200 # Fri Sep 06 18:33:20 2013 -0700 # Node ID 9ecb3ba6edabcc15065cbb93a0398c779369ce7c # Parent 43b3baa3c554d6e7cc4f9567f13f5a0265ecc08e WIP diff --git a/restlog.go b/restlog.go --- a/restlog.go +++ b/restlog.go @@ -13,9 +13,6 @@ "time" ) -var _ = os.Open - - type Logger interface { Writer(log string) (io.Writer, error) Reader(log string) (io.ReadSeeker, error) @@ -30,10 +27,10 @@ } func closeIfNeeded(value interface{}) error { - // switch v := value.(type) { - // case io.Closer: - // return v.Close() - // } + switch v := value.(type) { + case io.Closer: + return v.Close() + } return nil } @@ -56,37 +53,69 @@ return x, nil } -func addLog(req *http.Request, logger Logger) (string, int, error) { +func writeEntry(log io.Writer, prefix byte, entry []byte) error { + _, err := log.Write( + bytes.Join( + [][]byte{[]byte{prefix}, entry, []byte{'\n'}}, + []byte{}, + ), + ) + return err +} + +func addLog(req *http.Request, logger Logger) ([]byte, int, error) { input, err := validateInput(req) if err != nil { - return "", 400, err + return nil, http.StatusBadRequest, err } f, err := logger.Writer(req.URL.Path) if err != nil { - return "", 500, err + return nil, http.StatusInternalServerError, err } var t = time.Now().Format(time.RFC3339) - var line = fmt.Sprintf("%s %s\n", t, string(input)) - io.WriteString(f, line) - - if err := closeIfNeeded(logger); err != nil { - return line, 500, err + var entry = []byte(fmt.Sprintf("%s %s", t, input)) + if err := writeEntry(f, '+', entry); err != nil { + return nil, http.StatusInternalServerError, err + } + if err := closeIfNeeded(f); err != nil { + return nil, http.StatusInternalServerError, err } - return line, 200, nil + return entry, http.StatusOK, nil +} + +func delLog(req *http.Request, logger Logger) (int, error) { + input, err := validateInput(req) + if err != nil { + return http.StatusBadRequest, err + } + + f, err := logger.Writer(req.URL.Path) + if err != nil { + return http.StatusInternalServerError, err + } + + if err := writeEntry(f, '-', input); err != nil { + return http.StatusInternalServerError, err + } + if err := closeIfNeeded(f); err != nil { + return http.StatusInternalServerError, err + } + + return http.StatusOK, nil } func (self HTTPLog) ServeHTTP(w http.ResponseWriter, req *http.Request) { switch req.Method { case "POST": - line, code, err := addLog(req, self.logger) + entry, code, err := addLog(req, self.logger) if err != nil { http.Error(w, err.Error(), code) } else { - io.WriteString(w, line) + w.Write(entry) } return case "GET": @@ -129,21 +158,21 @@ return fileOpenLog(path, os.O_WRONLY) } -type MemoryLogger map[string][]byte +type MemoryLogger map[string]*bytes.Buffer -func (self MemoryLogger) handle(path string) []byte { - if self[path] == nil { - self[path] = make([]byte, 0) +func (self MemoryLogger) handle(path string) *bytes.Buffer { + if _, present := self[path]; !present { + self[path] = new(bytes.Buffer) } return self[path] } func (self MemoryLogger) Reader(path string) (io.ReadSeeker, error) { - return bytes.NewReader(self.handle(path)), nil + return bytes.NewReader(self.handle(path).Bytes()), nil } func (self MemoryLogger) Writer(path string) (io.Writer, error) { - return bytes.NewBuffer(self.handle(path)), nil + return self.handle(path), nil } func NewMemoryLogger() *MemoryLogger { @@ -156,8 +185,7 @@ func usage() { fmt.Fprintf( os.Stderr, - "Usage: restlog [address] (default %s)\n", - defaultAddr) + "Usage: restlog [address] (default %s)\n", defaultAddr) flag.PrintDefaults() os.Exit(2) } diff --git a/restlog_test.go b/restlog_test.go --- a/restlog_test.go +++ b/restlog_test.go @@ -32,25 +32,33 @@ return req } +func checkResponse(t *testing.T, w *httptest.ResponseRecorder, msg string) { + if w.Code != 200 { + t.Errorf("Bad HTTP code: %d", w.Code) + } + if !bytes.HasSuffix(w.Body.Bytes(), []byte(msg)) { + t.Fatalf("Invalid log: %q (%q)\n", w.Body.Bytes(), msg) + } +} + func TestAddLog(t *testing.T) { memorylog := NewMemoryLogger() var handler = NewHTTPLog(memorylog) - req := postRequest(t, "/log", "foo bar s:+1") for i := 0; i < 10; i++ { + req := postRequest(t, "log", "foo bar s:+1") w := httptest.NewRecorder() handler.ServeHTTP(w, req) - if w.Code != 200 { - t.Errorf("Bad HTTP code: %d", w.Code) - } + checkResponse(t, w, "foo bar s:+1") } if len(*memorylog) != 1 { t.Errorf("bad # of logs: %d", len(*memorylog)) } + for _, value := range *memorylog { - if len(value) < 100 { - t.Fatal("The logs look small", len(value), "< 100") + if value.Len() < 100 { + t.Fatalf("Logs look small: %d\n%q\n", value.Len(), value) } } }