github.com/cockroachdb/pebble@v1.1.1-0.20240513155919-3622ade60459/objstorage/remote/logging.go (about)

     1  // Copyright 2023 The LevelDB-Go and Pebble Authors. All rights reserved. Use
     2  // of this source code is governed by a BSD-style license that can be found in
     3  // the LICENSE file.
     4  
     5  package remote
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"io"
    11  	"sort"
    12  )
    13  
    14  // WithLogging wraps the given Storage implementation and emits logs for various
    15  // operations.
    16  func WithLogging(wrapped Storage, logf func(fmt string, args ...interface{})) Storage {
    17  	return &loggingStore{
    18  		logf:    logf,
    19  		wrapped: wrapped,
    20  	}
    21  }
    22  
    23  // loggingStore wraps a remote.Storage implementation and emits logs of the
    24  // operations.
    25  type loggingStore struct {
    26  	logf    func(fmt string, args ...interface{})
    27  	wrapped Storage
    28  }
    29  
    30  var _ Storage = (*loggingStore)(nil)
    31  
    32  func (l *loggingStore) Close() error {
    33  	l.logf("close")
    34  	return l.wrapped.Close()
    35  }
    36  
    37  func (l *loggingStore) ReadObject(
    38  	ctx context.Context, objName string,
    39  ) (_ ObjectReader, objSize int64, _ error) {
    40  	r, size, err := l.wrapped.ReadObject(ctx, objName)
    41  	l.logf("create reader for object %q: %s", objName, errOrPrintf(err, "%d bytes", size))
    42  	if err != nil {
    43  		return nil, 0, err
    44  	}
    45  	return &loggingReader{
    46  		l:       l,
    47  		name:    objName,
    48  		wrapped: r,
    49  	}, size, nil
    50  }
    51  
    52  type loggingReader struct {
    53  	l       *loggingStore
    54  	name    string
    55  	wrapped ObjectReader
    56  }
    57  
    58  var _ ObjectReader = (*loggingReader)(nil)
    59  
    60  func (l *loggingReader) ReadAt(ctx context.Context, p []byte, offset int64) error {
    61  	if err := l.wrapped.ReadAt(ctx, p, offset); err != nil {
    62  		l.l.logf("read object %q at %d (length %d): error %v", l.name, offset, len(p), err)
    63  		return err
    64  	}
    65  	l.l.logf("read object %q at %d (length %d)", l.name, offset, len(p))
    66  	return nil
    67  }
    68  
    69  func (l *loggingReader) Close() error {
    70  	l.l.logf("close reader for %q", l.name)
    71  	return l.wrapped.Close()
    72  }
    73  
    74  func (l *loggingStore) CreateObject(objName string) (io.WriteCloser, error) {
    75  	l.logf("create object %q", objName)
    76  	writer, err := l.wrapped.CreateObject(objName)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	return &loggingWriter{
    81  		l:           l,
    82  		name:        objName,
    83  		WriteCloser: writer,
    84  	}, nil
    85  }
    86  
    87  type loggingWriter struct {
    88  	l            *loggingStore
    89  	name         string
    90  	bytesWritten int64
    91  	io.WriteCloser
    92  }
    93  
    94  func (l *loggingWriter) Write(p []byte) (n int, err error) {
    95  	n, err = l.WriteCloser.Write(p)
    96  	l.bytesWritten += int64(n)
    97  	return n, err
    98  }
    99  
   100  func (l *loggingWriter) Close() error {
   101  	l.l.logf("close writer for %q after %d bytes", l.name, l.bytesWritten)
   102  	return l.WriteCloser.Close()
   103  }
   104  
   105  func (l *loggingStore) List(prefix, delimiter string) ([]string, error) {
   106  	l.logf("list (prefix=%q, delimiter=%q)", prefix, delimiter)
   107  	res, err := l.wrapped.List(prefix, delimiter)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	sorted := append([]string(nil), res...)
   112  	sort.Strings(sorted)
   113  	for _, s := range sorted {
   114  		l.logf(" - %s", s)
   115  	}
   116  	return res, nil
   117  }
   118  
   119  func (l *loggingStore) Delete(objName string) error {
   120  	l.logf("delete object %q", objName)
   121  	return l.wrapped.Delete(objName)
   122  }
   123  
   124  func (l *loggingStore) Size(objName string) (int64, error) {
   125  	size, err := l.wrapped.Size(objName)
   126  	l.logf("size of object %q: %s", objName, errOrPrintf(err, "%d", size))
   127  	return size, err
   128  }
   129  
   130  func errOrPrintf(err error, format string, args ...interface{}) string {
   131  	if err != nil {
   132  		return fmt.Sprintf("error: %v", err)
   133  	}
   134  	return fmt.Sprintf(format, args...)
   135  }
   136  
   137  func (l *loggingStore) IsNotExistError(err error) bool {
   138  	return l.wrapped.IsNotExistError(err)
   139  }