github.com/cockroachdb/pebble@v1.1.1-0.20240513155919-3622ade60459/vfs/logging_fs.go (about)

     1  // Copyright 2021 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 vfs
     6  
     7  import (
     8  	"io"
     9  	"os"
    10  )
    11  
    12  // WithLogging wraps an FS and logs filesystem modification operations to the
    13  // given logFn.
    14  func WithLogging(fs FS, logFn LogFn) FS {
    15  	return &loggingFS{
    16  		FS:    fs,
    17  		logFn: logFn,
    18  	}
    19  }
    20  
    21  // LogFn is a function that is used to capture a log when WithLogging is used.
    22  type LogFn func(fmt string, args ...interface{})
    23  
    24  type loggingFS struct {
    25  	FS
    26  	logFn LogFn
    27  }
    28  
    29  var _ FS = (*loggingFS)(nil)
    30  
    31  func (fs *loggingFS) Create(name string) (File, error) {
    32  	fs.logFn("create: %s", name)
    33  	f, err := fs.FS.Create(name)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	return newLoggingFile(f, name, fs.logFn), nil
    38  }
    39  
    40  func (fs *loggingFS) Open(name string, opts ...OpenOption) (File, error) {
    41  	fs.logFn("open: %s", name)
    42  	f, err := fs.FS.Open(name, opts...)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	return newLoggingFile(f, name, fs.logFn), nil
    47  }
    48  
    49  func (fs *loggingFS) OpenReadWrite(name string, opts ...OpenOption) (File, error) {
    50  	fs.logFn("open-read-write: %s", name)
    51  	f, err := fs.FS.OpenReadWrite(name, opts...)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  	return newLoggingFile(f, name, fs.logFn), nil
    56  }
    57  
    58  func (fs *loggingFS) Link(oldname, newname string) error {
    59  	fs.logFn("link: %s -> %s", oldname, newname)
    60  	return fs.FS.Link(oldname, newname)
    61  }
    62  
    63  func (fs *loggingFS) OpenDir(name string) (File, error) {
    64  	fs.logFn("open-dir: %s", name)
    65  	f, err := fs.FS.OpenDir(name)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	return newLoggingFile(f, name, fs.logFn), nil
    70  }
    71  
    72  func (fs *loggingFS) Rename(oldname, newname string) error {
    73  	fs.logFn("rename: %s -> %s", oldname, newname)
    74  	return fs.FS.Rename(oldname, newname)
    75  }
    76  
    77  func (fs *loggingFS) ReuseForWrite(oldname, newname string) (File, error) {
    78  	fs.logFn("reuseForWrite: %s -> %s", oldname, newname)
    79  	f, err := fs.FS.ReuseForWrite(oldname, newname)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	return newLoggingFile(f, newname, fs.logFn), nil
    84  }
    85  
    86  func (fs *loggingFS) MkdirAll(dir string, perm os.FileMode) error {
    87  	fs.logFn("mkdir-all: %s %#o", dir, perm)
    88  	return fs.FS.MkdirAll(dir, perm)
    89  }
    90  
    91  func (fs *loggingFS) Lock(name string) (io.Closer, error) {
    92  	fs.logFn("lock: %s", name)
    93  	return fs.FS.Lock(name)
    94  }
    95  
    96  func (fs loggingFS) Remove(name string) error {
    97  	fs.logFn("remove: %s", name)
    98  	err := fs.FS.Remove(name)
    99  	return err
   100  }
   101  
   102  func (fs loggingFS) RemoveAll(name string) error {
   103  	fs.logFn("remove-all: %s", name)
   104  	err := fs.FS.RemoveAll(name)
   105  	return err
   106  }
   107  
   108  type loggingFile struct {
   109  	File
   110  	name  string
   111  	logFn LogFn
   112  }
   113  
   114  var _ File = (*loggingFile)(nil)
   115  
   116  func newLoggingFile(f File, name string, logFn LogFn) *loggingFile {
   117  	return &loggingFile{
   118  		File:  f,
   119  		name:  name,
   120  		logFn: logFn,
   121  	}
   122  }
   123  
   124  func (f *loggingFile) Close() error {
   125  	f.logFn("close: %s", f.name)
   126  	return f.File.Close()
   127  }
   128  
   129  func (f *loggingFile) Sync() error {
   130  	f.logFn("sync: %s", f.name)
   131  	return f.File.Sync()
   132  }
   133  
   134  func (f *loggingFile) SyncData() error {
   135  	f.logFn("sync-data: %s", f.name)
   136  	return f.File.SyncData()
   137  }
   138  
   139  func (f *loggingFile) SyncTo(length int64) (fullSync bool, err error) {
   140  	f.logFn("sync-to(%d): %s", length, f.name)
   141  	return f.File.SyncTo(length)
   142  }
   143  
   144  func (f *loggingFile) ReadAt(p []byte, offset int64) (int, error) {
   145  	f.logFn("read-at(%d, %d): %s", offset, len(p), f.name)
   146  	return f.File.ReadAt(p, offset)
   147  }
   148  
   149  func (f *loggingFile) WriteAt(p []byte, offset int64) (int, error) {
   150  	f.logFn("write-at(%d, %d): %s", offset, len(p), f.name)
   151  	return f.File.WriteAt(p, offset)
   152  }
   153  
   154  func (f *loggingFile) Prefetch(offset int64, length int64) error {
   155  	f.logFn("prefetch(%d, %d): %s", offset, length, f.name)
   156  	return f.File.Prefetch(offset, length)
   157  }