//go:build example // +build example package main import ( "fmt" "io" "log" "os" "runtime/debug" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/s3/s3manager" ) // Usage: // go run -tags example // // Example: // AWS_REGION=us-west-2 AWS_PROFILE=default go run . "mybucket" "10MB.file" ./10MB.file func main() { sess, err := session.NewSession() if err != nil { log.Fatalf("failed to load session, %v", err) } uploader := s3manager.NewUploader(sess) file, err := os.Open(os.Args[3]) if err != nil { log.Fatalf("failed to open file, %v", err) } defer file.Close() // Wrap the readSeeker with a logger that will log usage, and stack traces // on errors. readLogger := NewReadLogger(file, sess.Config.Logger) // Upload with read logger resp, err := uploader.Upload(&s3manager.UploadInput{ Bucket: &os.Args[1], Key: &os.Args[2], Body: readLogger, }, func(u *s3manager.Uploader) { u.Concurrency = 1 u.RequestOptions = append(u.RequestOptions, func(r *request.Request) { }) }) fmt.Println(resp, err) } // Logger is a logger use for logging the readers usage. type Logger interface { Log(args ...interface{}) } // ReadSeeker interface provides the interface for a Reader, Seeker, and ReadAt. type ReadSeeker interface { io.ReadSeeker io.ReaderAt } // ReadLogger wraps an reader with logging for access. type ReadLogger struct { reader ReadSeeker logger Logger } // NewReadLogger a ReadLogger that wraps the passed in ReadSeeker (Reader, // Seeker, ReadAt) with a logger. func NewReadLogger(r ReadSeeker, logger Logger) *ReadLogger { return &ReadLogger{ reader: r, logger: logger, } } // Seek offsets the reader's current position for the next read. func (s *ReadLogger) Seek(offset int64, mode int) (int64, error) { newOffset, err := s.reader.Seek(offset, mode) msg := fmt.Sprintf( "ReadLogger.Seek(offset:%d, mode:%d) (newOffset:%d, err:%v)", offset, mode, newOffset, err) if err != nil { msg += fmt.Sprintf("\n\tStack:\n%s", string(debug.Stack())) } s.logger.Log(msg) return newOffset, err } // Read attempts to read from the reader, returning the bytes read, or error. func (s *ReadLogger) Read(b []byte) (int, error) { n, err := s.reader.Read(b) msg := fmt.Sprintf( "ReadLogger.Read(len(bytes):%d) (read:%d, err:%v)", len(b), n, err) if err != nil { msg += fmt.Sprintf("\n\tStack:\n%s", string(debug.Stack())) } s.logger.Log(msg) return n, err } // ReadAt will read the underlying reader starting at the offset. func (s *ReadLogger) ReadAt(b []byte, offset int64) (int, error) { n, err := s.reader.ReadAt(b, offset) msg := fmt.Sprintf( "ReadLogger.ReadAt(len(bytes):%d, offset:%d) (read:%d, err:%v)", len(b), offset, n, err) if err != nil { msg += fmt.Sprintf("\n\tStack:\n%s", string(debug.Stack())) } s.logger.Log(msg) return n, err }