Skip to content

Commit 13bd88e

Browse files
authored
Merge pull request moby#4109 from sipsma/cache-debug-logs
2 parents a1deb3e + 45b19d3 commit 13bd88e

File tree

6 files changed

+148
-23
lines changed

6 files changed

+148
-23
lines changed

cache/refs.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ func (cr *cacheRecord) remove(ctx context.Context, removeSnapshot bool) (rerr er
444444
"id": cr.ID(),
445445
"refCount": len(cr.refs),
446446
"removeSnapshot": removeSnapshot,
447-
"stack": bklog.LazyStackTrace{},
447+
"stack": bklog.TraceLevelOnlyStack(),
448448
})
449449
if rerr != nil {
450450
l = l.WithError(rerr)
@@ -488,7 +488,7 @@ func (sr *immutableRef) traceLogFields() logrus.Fields {
488488
"refID": fmt.Sprintf("%p", sr),
489489
"newRefCount": len(sr.refs),
490490
"mutable": false,
491-
"stack": bklog.LazyStackTrace{},
491+
"stack": bklog.TraceLevelOnlyStack(),
492492
}
493493
if sr.equalMutable != nil {
494494
m["equalMutableID"] = sr.equalMutable.ID()
@@ -628,7 +628,7 @@ func (sr *mutableRef) traceLogFields() logrus.Fields {
628628
"refID": fmt.Sprintf("%p", sr),
629629
"newRefCount": len(sr.refs),
630630
"mutable": true,
631-
"stack": bklog.LazyStackTrace{},
631+
"stack": bklog.TraceLevelOnlyStack(),
632632
}
633633
if sr.equalMutable != nil {
634634
m["equalMutableID"] = sr.equalMutable.ID()

solver/cachekey.go

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,56 @@ type CacheKeyWithSelector struct {
2424
CacheKey ExportableCacheKey
2525
}
2626

27+
func (ck CacheKeyWithSelector) TraceFields() map[string]any {
28+
fields := ck.CacheKey.TraceFields()
29+
fields["selector"] = ck.Selector.String()
30+
return fields
31+
}
32+
2733
type CacheKey struct {
2834
mu sync.RWMutex
2935

30-
ID string
31-
deps [][]CacheKeyWithSelector // only [][]*inMemoryCacheKey
36+
ID string
37+
deps [][]CacheKeyWithSelector
38+
// digest is the digest returned by the CacheMap implementation of this op
3239
digest digest.Digest
40+
// vtx is the LLB digest that this op was created for
3341
vtx digest.Digest
3442
output Index
3543
ids map[*cacheManager]string
3644

3745
indexIDs []string
3846
}
3947

48+
func (ck *CacheKey) TraceFields() map[string]any {
49+
ck.mu.RLock()
50+
defer ck.mu.RUnlock()
51+
idsMap := map[string]string{}
52+
for cm, id := range ck.ids {
53+
idsMap[cm.ID()] = id
54+
}
55+
56+
// don't recurse more than one level in showing deps
57+
depsMap := make([]map[string]string, len(ck.deps))
58+
for i, deps := range ck.deps {
59+
depsMap[i] = map[string]string{}
60+
for _, ck := range deps {
61+
depsMap[i]["id"] = ck.CacheKey.ID
62+
depsMap[i]["selector"] = ck.Selector.String()
63+
}
64+
}
65+
66+
return map[string]any{
67+
"id": ck.ID,
68+
"digest": ck.digest,
69+
"vtx": ck.vtx,
70+
"output": ck.output,
71+
"indexIDs": ck.indexIDs,
72+
"ids": idsMap,
73+
"deps": depsMap,
74+
}
75+
}
76+
4077
func (ck *CacheKey) Deps() [][]CacheKeyWithSelector {
4178
ck.mu.RLock()
4279
defer ck.mu.RUnlock()

solver/cachemanager.go

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/moby/buildkit/identity"
1111
"github.com/moby/buildkit/util/bklog"
1212
digest "github.com/opencontainers/go-digest"
13+
"github.com/sirupsen/logrus"
1314
)
1415

1516
// NewInMemoryCacheManager creates a new in-memory cache manager
@@ -55,7 +56,28 @@ func (c *cacheManager) ID() string {
5556
return c.id
5657
}
5758

58-
func (c *cacheManager) Query(deps []CacheKeyWithSelector, input Index, dgst digest.Digest, output Index) ([]*CacheKey, error) {
59+
func (c *cacheManager) Query(deps []CacheKeyWithSelector, input Index, dgst digest.Digest, output Index) (rcks []*CacheKey, rerr error) {
60+
depsField := make([]map[string]any, len(deps))
61+
for i, dep := range deps {
62+
depsField[i] = dep.TraceFields()
63+
}
64+
lg := bklog.G(context.TODO()).WithFields(logrus.Fields{
65+
"cache_manager": c.id,
66+
"op": "query",
67+
"deps": depsField,
68+
"input": input,
69+
"digest": dgst,
70+
"output": output,
71+
"stack": bklog.TraceLevelOnlyStack(),
72+
})
73+
defer func() {
74+
rcksField := make([]map[string]any, len(rcks))
75+
for i, rck := range rcks {
76+
rcksField[i] = rck.TraceFields()
77+
}
78+
lg.WithError(rerr).WithField("return_cachekeys", rcksField).Trace("cache manager")
79+
}()
80+
5981
c.mu.RLock()
6082
defer c.mu.RUnlock()
6183

@@ -112,7 +134,21 @@ func (c *cacheManager) Query(deps []CacheKeyWithSelector, input Index, dgst dige
112134
return keys, nil
113135
}
114136

115-
func (c *cacheManager) Records(ctx context.Context, ck *CacheKey) ([]*CacheRecord, error) {
137+
func (c *cacheManager) Records(ctx context.Context, ck *CacheKey) (rrecs []*CacheRecord, rerr error) {
138+
lg := bklog.G(context.TODO()).WithFields(logrus.Fields{
139+
"cache_manager": c.id,
140+
"op": "records",
141+
"cachekey": ck.TraceFields(),
142+
"stack": bklog.TraceLevelOnlyStack(),
143+
})
144+
defer func() {
145+
rrercsField := make([]map[string]any, len(rrecs))
146+
for i, rrec := range rrecs {
147+
rrercsField[i] = rrec.TraceFields()
148+
}
149+
lg.WithError(rerr).WithField("return_records", rrercsField).Trace("cache manager")
150+
}()
151+
116152
outs := make([]*CacheRecord, 0)
117153
if err := c.backend.WalkResults(c.getID(ck), func(r CacheResult) error {
118154
if c.results.Exists(ctx, r.ID) {
@@ -132,7 +168,17 @@ func (c *cacheManager) Records(ctx context.Context, ck *CacheKey) ([]*CacheRecor
132168
return outs, nil
133169
}
134170

135-
func (c *cacheManager) Load(ctx context.Context, rec *CacheRecord) (Result, error) {
171+
func (c *cacheManager) Load(ctx context.Context, rec *CacheRecord) (rres Result, rerr error) {
172+
lg := bklog.G(context.TODO()).WithFields(logrus.Fields{
173+
"cache_manager": c.id,
174+
"op": "load",
175+
"record": rec.TraceFields(),
176+
"stack": bklog.TraceLevelOnlyStack(),
177+
})
178+
defer func() {
179+
lg.WithError(rerr).WithField("return_result", rres.ID()).Trace("cache manager")
180+
}()
181+
136182
c.mu.RLock()
137183
defer c.mu.RUnlock()
138184

@@ -150,6 +196,14 @@ type LoadedResult struct {
150196
CacheKey *CacheKey
151197
}
152198

199+
func (r *LoadedResult) TraceFields() map[string]any {
200+
return map[string]any{
201+
"result": r.Result.ID(),
202+
"cache_result": r.CacheResult.ID,
203+
"cache_key": r.CacheKey.TraceFields(),
204+
}
205+
}
206+
153207
func (c *cacheManager) filterResults(m map[string]Result, ck *CacheKey, visited map[string]struct{}) (results []LoadedResult, err error) {
154208
id := c.getID(ck)
155209
if _, ok := visited[id]; ok {
@@ -187,7 +241,21 @@ func (c *cacheManager) filterResults(m map[string]Result, ck *CacheKey, visited
187241
return
188242
}
189243

190-
func (c *cacheManager) LoadWithParents(ctx context.Context, rec *CacheRecord) ([]LoadedResult, error) {
244+
func (c *cacheManager) LoadWithParents(ctx context.Context, rec *CacheRecord) (rres []LoadedResult, rerr error) {
245+
lg := bklog.G(context.TODO()).WithFields(logrus.Fields{
246+
"cache_manager": c.id,
247+
"op": "load_with_parents",
248+
"record": rec.TraceFields(),
249+
"stack": bklog.TraceLevelOnlyStack(),
250+
})
251+
defer func() {
252+
rresField := make([]map[string]any, len(rres))
253+
for i, rres := range rres {
254+
rresField[i] = rres.TraceFields()
255+
}
256+
lg.WithError(rerr).WithField("return_results", rresField).Trace("cache manager")
257+
}()
258+
191259
lwp, ok := c.results.(interface {
192260
LoadWithParents(context.Context, CacheResult) (map[string]Result, error)
193261
})
@@ -226,7 +294,17 @@ func (c *cacheManager) LoadWithParents(ctx context.Context, rec *CacheRecord) ([
226294
return results, nil
227295
}
228296

229-
func (c *cacheManager) Save(k *CacheKey, r Result, createdAt time.Time) (*ExportableCacheKey, error) {
297+
func (c *cacheManager) Save(k *CacheKey, r Result, createdAt time.Time) (rck *ExportableCacheKey, rerr error) {
298+
lg := bklog.G(context.TODO()).WithFields(logrus.Fields{
299+
"cache_manager": c.id,
300+
"op": "save",
301+
"result": r.ID(),
302+
"stack": bklog.TraceLevelOnlyStack(),
303+
})
304+
defer func() {
305+
lg.WithError(rerr).WithField("return_cachekey", rck.TraceFields()).Trace("cache manager")
306+
}()
307+
230308
c.mu.Lock()
231309
defer c.mu.Unlock()
232310

solver/llbsolver/mounts/mount.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ type cacheRefShare struct {
483483
func (r *cacheRefShare) clone(ctx context.Context) cache.MutableRef {
484484
bklog.G(ctx).WithFields(map[string]any{
485485
"key": r.key,
486-
"stack": bklog.LazyStackTrace{},
486+
"stack": bklog.TraceLevelOnlyStack(),
487487
}).Trace("cloning cache mount ref share")
488488
cacheRef := &cacheRef{cacheRefShare: r}
489489
if cacheRefCloneHijack != nil {
@@ -498,7 +498,7 @@ func (r *cacheRefShare) clone(ctx context.Context) cache.MutableRef {
498498
func (r *cacheRefShare) release(ctx context.Context) error {
499499
bklog.G(ctx).WithFields(map[string]any{
500500
"key": r.key,
501-
"stack": bklog.LazyStackTrace{},
501+
"stack": bklog.TraceLevelOnlyStack(),
502502
}).Trace("releasing cache mount ref share main")
503503
if r.main != nil {
504504
delete(r.main.shares, r.key)
@@ -516,7 +516,7 @@ type cacheRef struct {
516516
func (r *cacheRef) Release(ctx context.Context) error {
517517
bklog.G(ctx).WithFields(map[string]any{
518518
"key": r.key,
519-
"stack": bklog.LazyStackTrace{},
519+
"stack": bklog.TraceLevelOnlyStack(),
520520
}).Trace("releasing cache mount ref share")
521521
if r.main != nil {
522522
r.main.mu.Lock()

solver/types.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,17 @@ type CacheRecord struct {
228228
key *CacheKey
229229
}
230230

231+
func (ck *CacheRecord) TraceFields() map[string]any {
232+
return map[string]any{
233+
"id": ck.ID,
234+
"size": ck.Size,
235+
"createdAt": ck.CreatedAt,
236+
"priority": ck.Priority,
237+
"cache_manager": ck.cacheManager.ID(),
238+
"cache_key": ck.key.TraceFields(),
239+
}
240+
}
241+
231242
// CacheManager determines if there is a result that matches the cache keys
232243
// generated during the build that could be reused instead of fully
233244
// reevaluating the vertex and its inputs. There can be multiple cache

util/bklog/log.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,13 @@ func GetLogger(ctx context.Context) (l *logrus.Entry) {
6363
return l
6464
}
6565

66-
// LazyStackTrace lets you include a stack trace as a field's value in a log but only
67-
// call it when the log level is actually enabled.
68-
type LazyStackTrace struct{}
69-
70-
func (LazyStackTrace) String() string {
71-
return string(debug.Stack())
72-
}
73-
74-
func (LazyStackTrace) MarshalText() ([]byte, error) {
75-
return debug.Stack(), nil
66+
// TraceLevelOnlyStack returns a stack trace for the current goroutine only if
67+
// trace level logs are enabled; otherwise it returns an empty string. This ensure
68+
// we only pay the cost of generating a stack trace when the log entry will actually
69+
// be emitted.
70+
func TraceLevelOnlyStack() string {
71+
if logrus.GetLevel() == logrus.TraceLevel {
72+
return string(debug.Stack())
73+
}
74+
return ""
7675
}

0 commit comments

Comments
 (0)