2 files changed, 68 insertions(+), 32 deletions(-)

M restlog.go
M restlog_test.go
M restlog.go +54 -26
@@ 13,9 13,6 @@ import (
 	"time"
 )
 
-var _ = os.Open
-
-
 type Logger interface {
 	Writer(log string) (io.Writer, error)
 	Reader(log string) (io.ReadSeeker, error)

          
@@ 30,10 27,10 @@ func NewHTTPLog(logger Logger) HTTPLog {
 }
 
 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 @@ func validateInput(req *http.Request) ([
 	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 @@ func (h FileLogger) Writer(path string) 
 	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 @@ var defaultAddr = ":8080"
 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)
 }

          
M restlog_test.go +14 -6
@@ 32,25 32,33 @@ func getRequest(t *testing.T, log string
 	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)
 		}
 	}
 }