Skip to content

Commit

Permalink
Merge pull request #22 from shabbyrobe/feature/logger
Browse files Browse the repository at this point in the history
Pluggable logger
  • Loading branch information
johannesboyne authored Jan 19, 2019
2 parents 074ae5e + a58e1f8 commit 62d688c
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 40 deletions.
1 change: 1 addition & 0 deletions cmd/gofakes3/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ func run() error {
gofakes3.WithTimeSource(timeSource),
gofakes3.WithTimeSkewLimit(timeSkewLimit),
gofakes3.WithIntegrityCheck(!noIntegrity),
gofakes3.WithLogger(gofakes3.GlobalLog()),
)
return listenAndServe(host, faker.Server())
}
Expand Down
12 changes: 6 additions & 6 deletions cors.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gofakes3

import (
"log"
"net/http"
"regexp"
"strings"
Expand All @@ -27,11 +26,12 @@ var (
bucketRewritePattern = regexp.MustCompile("(127.0.0.1:\\d{1,7})|(.localhost:\\d{1,7})|(localhost:\\d{1,7})")
)

type WithCORS struct {
r http.Handler
type withCORS struct {
r http.Handler
log Logger
}

func (s *WithCORS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
func (s *withCORS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD")
w.Header().Set("Access-Control-Allow-Headers", corsHeadersString)
Expand All @@ -44,14 +44,14 @@ func (s *WithCORS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// this is due to some inconsistencies in the AWS SDKs
bucket := bucketRewritePattern.ReplaceAllString(r.Host, "")
if len(bucket) > 0 {
log.Println("rewrite bucket ->", bucket)
s.log.Print(LogInfo, "rewrite bucket ->", bucket)
p := r.URL.Path
r.URL.Path = "/" + bucket
if p != "/" {
r.URL.Path += p
}
}
log.Println("=>", r.URL)
s.log.Print(LogInfo, "=>", r.URL)

s.r.ServeHTTP(w, r)
}
64 changes: 33 additions & 31 deletions gofakes3.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"fmt"
"io"
"io/ioutil"
"log"
"math"
"net/http"
"strconv"
Expand Down Expand Up @@ -61,12 +60,13 @@ type GoFakeS3 struct {
metadataSizeLimit int
integrityCheck bool
uploader *uploader
log Logger
}

// Setup a new fake object storage
// New creates a new GoFakeS3 using the supplied Backend. Backends are pluggable.
// Several Backend implementations ship with GoFakeS3, which can be found in the
// gofakes3/backends package.
func New(backend Backend, options ...Option) *GoFakeS3 {
log.Println("locals3 db created or opened")

s3 := &GoFakeS3{
storage: backend,
timeSkew: DefaultSkewLimit,
Expand All @@ -77,6 +77,9 @@ func New(backend Backend, options ...Option) *GoFakeS3 {
for _, opt := range options {
opt(s3)
}
if s3.log == nil {
s3.log = DiscardLog()
}
if s3.timeSource == nil {
s3.timeSource = DefaultTimeSource()
}
Expand All @@ -86,7 +89,7 @@ func New(backend Backend, options ...Option) *GoFakeS3 {

// Create the AWS S3 API
func (g *GoFakeS3) Server() http.Handler {
wc := &WithCORS{http.HandlerFunc(g.routeBase)}
wc := &withCORS{r: http.HandlerFunc(g.routeBase), log: g.log}

hf := func(w http.ResponseWriter, rq *http.Request) {
timeHdr := rq.Header.Get("x-amz-date")
Expand All @@ -111,7 +114,7 @@ func (g *GoFakeS3) Server() http.Handler {
func (g *GoFakeS3) httpError(w http.ResponseWriter, r *http.Request, err error) {
resp := ensureErrorResponse(err, "") // FIXME: request id
if resp.ErrorCode() == ErrInternal {
log.Println(err)
g.log.Print(LogErr, err)
}

w.WriteHeader(resp.ErrorCode().Status())
Expand All @@ -121,7 +124,7 @@ func (g *GoFakeS3) httpError(w http.ResponseWriter, r *http.Request, err error)

w.Write([]byte(xml.Header))
if err := g.xmlEncoder(w).Encode(resp); err != nil {
log.Println(err)
g.log.Print(LogErr, err)
return
}
}
Expand Down Expand Up @@ -155,12 +158,12 @@ func (g *GoFakeS3) getBuckets(w http.ResponseWriter, r *http.Request) error {

// GetBucket lists the contents of a bucket.
func (g *GoFakeS3) getBucket(bucketName string, w http.ResponseWriter, r *http.Request) error {
log.Println("GET BUCKET")
g.log.Print(LogInfo, "GET BUCKET")

prefix := prefixFromQuery(r.URL.Query())

log.Println("bucketname:", bucketName)
log.Println("prefix :", prefix)
g.log.Print(LogInfo, "bucketname:", bucketName)
g.log.Print(LogInfo, "prefix :", prefix)

bucket, err := g.storage.GetBucket(bucketName, prefix)
if err != nil {
Expand All @@ -180,7 +183,7 @@ func (g *GoFakeS3) getBucket(bucketName string, w http.ResponseWriter, r *http.R

// CreateBucket creates a new S3 bucket in the BoltDB storage.
func (g *GoFakeS3) createBucket(bucket string, w http.ResponseWriter, r *http.Request) error {
log.Println("CREATE BUCKET:", bucket)
g.log.Print(LogInfo, "CREATE BUCKET:", bucket)

if err := ValidateBucketName(bucket); err != nil {
return err
Expand All @@ -197,14 +200,14 @@ func (g *GoFakeS3) createBucket(bucket string, w http.ResponseWriter, r *http.Re

// DeleteBucket creates a new S3 bucket in the BoltDB storage.
func (g *GoFakeS3) deleteBucket(bucket string, w http.ResponseWriter, r *http.Request) error {
log.Println("DELETE BUCKET:", bucket)
g.log.Print(LogInfo, "DELETE BUCKET:", bucket)
return g.storage.DeleteBucket(bucket)
}

// HeadBucket checks whether a bucket exists.
func (g *GoFakeS3) headBucket(bucket string, w http.ResponseWriter, r *http.Request) error {
log.Println("HEAD BUCKET", bucket)
log.Println("bucketname:", bucket)
g.log.Print(LogInfo, "HEAD BUCKET", bucket)
g.log.Print(LogInfo, "bucketname:", bucket)

if err := g.ensureBucketExists(bucket); err != nil {
return err
Expand All @@ -219,10 +222,9 @@ func (g *GoFakeS3) headBucket(bucket string, w http.ResponseWriter, r *http.Requ

// GetObject retrievs a bucket object.
func (g *GoFakeS3) getObject(bucket, object string, w http.ResponseWriter, r *http.Request) error {
log.Println("GET OBJECT")

log.Println("Bucket:", bucket)
log.Println("└── Object:", object)
g.log.Print(LogInfo, "GET OBJECT")
g.log.Print(LogInfo, "Bucket:", bucket)
g.log.Print(LogInfo, "└── Object:", object)

obj, err := g.storage.GetObject(bucket, object)
if err != nil {
Expand All @@ -249,7 +251,7 @@ func (g *GoFakeS3) getObject(bucket, object string, w http.ResponseWriter, r *ht

// CreateObject (Browser Upload) creates a new S3 object.
func (g *GoFakeS3) createObjectBrowserUpload(bucket string, w http.ResponseWriter, r *http.Request) error {
log.Println("CREATE OBJECT THROUGH BROWSER UPLOAD")
g.log.Print(LogInfo, "CREATE OBJECT THROUGH BROWSER UPLOAD")

const _24MB = (1 << 20) * 24 // maximum amount of memory before temp files are used
if err := r.ParseMultipartForm(_24MB); nil != err {
Expand All @@ -262,8 +264,8 @@ func (g *GoFakeS3) createObjectBrowserUpload(bucket string, w http.ResponseWrite
}
key := keyValues[0]

log.Println("(BUC)", bucket)
log.Println("(KEY)", key)
g.log.Print(LogInfo, "(BUC)", bucket)
g.log.Print(LogInfo, "(KEY)", key)

fileValues := r.MultipartForm.File["file"]
if len(fileValues) != 1 {
Expand Down Expand Up @@ -302,7 +304,7 @@ func (g *GoFakeS3) createObjectBrowserUpload(bucket string, w http.ResponseWrite

// CreateObject creates a new S3 object.
func (g *GoFakeS3) createObject(bucket, object string, w http.ResponseWriter, r *http.Request) (err error) {
log.Println("CREATE OBJECT:", bucket, object)
g.log.Print(LogInfo, "CREATE OBJECT:", bucket, object)

meta, err := metadataHeaders(r.Header, g.timeSource.Now(), g.metadataSizeLimit)
if err != nil {
Expand Down Expand Up @@ -347,7 +349,7 @@ func (g *GoFakeS3) createObject(bucket, object string, w http.ResponseWriter, r

// deleteObject deletes a S3 object from the bucket.
func (g *GoFakeS3) deleteObject(bucket, object string, w http.ResponseWriter, r *http.Request) error {
log.Println("DELETE:", bucket, object)
g.log.Print(LogInfo, "DELETE:", bucket, object)
if err := g.storage.DeleteObject(bucket, object); err != nil {
return err
}
Expand All @@ -359,7 +361,7 @@ func (g *GoFakeS3) deleteObject(bucket, object string, w http.ResponseWriter, r
// deleteMulti deletes multiple S3 objects from the bucket.
// https://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html
func (g *GoFakeS3) deleteMulti(bucket string, w http.ResponseWriter, r *http.Request) error {
log.Println("delete multi", bucket)
g.log.Print(LogInfo, "delete multi", bucket)

var in DeleteRequest

Expand Down Expand Up @@ -395,10 +397,10 @@ func (g *GoFakeS3) deleteMulti(bucket string, w http.ResponseWriter, r *http.Req

// HeadObject retrieves only meta information of an object and not the whole.
func (g *GoFakeS3) headObject(bucket, object string, w http.ResponseWriter, r *http.Request) error {
log.Println("HEAD OBJECT")
g.log.Print(LogInfo, "HEAD OBJECT")

log.Println("Bucket:", bucket)
log.Println("└── Object:", object)
g.log.Print(LogInfo, "Bucket:", bucket)
g.log.Print(LogInfo, "└── Object:", object)

obj, err := g.storage.HeadObject(bucket, object)
if err != nil {
Expand All @@ -422,7 +424,7 @@ func (g *GoFakeS3) headObject(bucket, object string, w http.ResponseWriter, r *h
}

func (g *GoFakeS3) initiateMultipartUpload(bucket, object string, w http.ResponseWriter, r *http.Request) error {
log.Println("initiate multipart upload", bucket, object)
g.log.Print(LogInfo, "initiate multipart upload", bucket, object)

meta, err := metadataHeaders(r.Header, g.timeSource.Now(), g.metadataSizeLimit)
if err != nil {
Expand All @@ -445,7 +447,7 @@ func (g *GoFakeS3) initiateMultipartUpload(bucket, object string, w http.Respons
// part. There is no size limit on the last part of your multipart upload.
//
func (g *GoFakeS3) putMultipartUploadPart(bucket, object string, uploadID UploadID, w http.ResponseWriter, r *http.Request) error {
log.Println("put multipart upload", bucket, object, uploadID)
g.log.Print(LogInfo, "put multipart upload", bucket, object, uploadID)

partNumber, err := strconv.ParseInt(r.URL.Query().Get("partNumber"), 10, 0)
if err != nil || partNumber <= 0 || partNumber > MaxUploadPartNumber {
Expand Down Expand Up @@ -499,13 +501,13 @@ func (g *GoFakeS3) putMultipartUploadPart(bucket, object string, uploadID Upload
}

func (g *GoFakeS3) abortMultipartUpload(bucket, object string, uploadID UploadID, w http.ResponseWriter, r *http.Request) error {
log.Println("abort multipart upload", bucket, object, uploadID)
g.log.Print(LogInfo, "abort multipart upload", bucket, object, uploadID)
_, err := g.uploader.Complete(bucket, object, uploadID)
return err
}

func (g *GoFakeS3) completeMultipartUpload(bucket, object string, uploadID UploadID, w http.ResponseWriter, r *http.Request) error {
log.Println("complete multipart upload", bucket, object, uploadID)
g.log.Print(LogInfo, "complete multipart upload", bucket, object, uploadID)

body, err := ioutil.ReadAll(r.Body)
defer r.Body.Close()
Expand Down
15 changes: 12 additions & 3 deletions gofakes3_internal_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package gofakes3

import (
"bytes"
"encoding/xml"
"fmt"
"log"
"net/http/httptest"
"testing"
)
Expand All @@ -29,9 +31,13 @@ func TestHttpError(t *testing.T) {
}

func TestHttpErrorWriteFailure(t *testing.T) {
// FIXME: with a pluggable logger, we can intercept the log message to
// verify the write error is handled.
var g GoFakeS3
var buf bytes.Buffer
std := log.New(&buf, "", 0)
logger := StdLog(std)
var g = GoFakeS3{
log: logger,
}

rq := httptest.NewRequest("GET", "/", nil)
rs := httptest.NewRecorder()
g.httpError(&failingResponseWriter{rs}, rq, ErrNoSuchBucket)
Expand All @@ -41,6 +47,9 @@ func TestHttpErrorWriteFailure(t *testing.T) {
if rs.Body.Len() != 0 {
t.Fatal()
}
if buf.String() != "ERR nope\n" {
t.Fatal()
}
}

type failingResponseWriter struct {
Expand Down
4 changes: 4 additions & 0 deletions init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ func newTestServer(t *testing.T, opts ...testServerOption) *testServer {
ts.GoFakeS3 = gofakes3.New(ts.backend,
gofakes3.WithTimeSource(ts.TimeSourceAdvancer),
gofakes3.WithTimeSkewLimit(0),

// TestMain wires the stdlib's global logger up to a file already,
// which this takes advantage of:
gofakes3.WithGlobalLog(),
)
ts.server = httptest.NewServer(ts.GoFakeS3.Server())

Expand Down
Loading

0 comments on commit 62d688c

Please sign in to comment.