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