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