| package storage |
| |
| import ( |
| "context" |
| "expvar" |
| "sync/atomic" |
| |
| dcontext "github.com/docker/distribution/context" |
| "github.com/docker/distribution/registry/storage/cache" |
| ) |
| |
| type blobStatCollector struct { |
| metrics cache.Metrics |
| } |
| |
| func (bsc *blobStatCollector) Hit() { |
| atomic.AddUint64(&bsc.metrics.Requests, 1) |
| atomic.AddUint64(&bsc.metrics.Hits, 1) |
| } |
| |
| func (bsc *blobStatCollector) Miss() { |
| atomic.AddUint64(&bsc.metrics.Requests, 1) |
| atomic.AddUint64(&bsc.metrics.Misses, 1) |
| } |
| |
| func (bsc *blobStatCollector) Metrics() cache.Metrics { |
| return bsc.metrics |
| } |
| |
| func (bsc *blobStatCollector) Logger(ctx context.Context) cache.Logger { |
| return dcontext.GetLogger(ctx) |
| } |
| |
| // blobStatterCacheMetrics keeps track of cache metrics for blob descriptor |
| // cache requests. Note this is kept globally and made available via expvar. |
| // For more detailed metrics, its recommend to instrument a particular cache |
| // implementation. |
| var blobStatterCacheMetrics cache.MetricsTracker = &blobStatCollector{} |
| |
| func init() { |
| registry := expvar.Get("registry") |
| if registry == nil { |
| registry = expvar.NewMap("registry") |
| } |
| |
| cache := registry.(*expvar.Map).Get("cache") |
| if cache == nil { |
| cache = &expvar.Map{} |
| cache.(*expvar.Map).Init() |
| registry.(*expvar.Map).Set("cache", cache) |
| } |
| |
| storage := cache.(*expvar.Map).Get("storage") |
| if storage == nil { |
| storage = &expvar.Map{} |
| storage.(*expvar.Map).Init() |
| cache.(*expvar.Map).Set("storage", storage) |
| } |
| |
| storage.(*expvar.Map).Set("blobdescriptor", expvar.Func(func() interface{} { |
| // no need for synchronous access: the increments are atomic and |
| // during reading, we don't care if the data is up to date. The |
| // numbers will always *eventually* be reported correctly. |
| return blobStatterCacheMetrics |
| })) |
| } |