github.com/m3db/m3@v1.5.0/src/dbnode/storage/bootstrap/bootstrapper/fs/source_instrumentation.go (about) 1 // Copyright (c) 2021 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package fs 22 23 import ( 24 "time" 25 26 "github.com/opentracing/opentracing-go" 27 opentracinglog "github.com/opentracing/opentracing-go/log" 28 "github.com/uber-go/tally" 29 "go.uber.org/zap" 30 "go.uber.org/zap/zapcore" 31 32 "github.com/m3db/m3/src/dbnode/tracepoint" 33 "github.com/m3db/m3/src/x/clock" 34 "github.com/m3db/m3/src/x/context" 35 "github.com/m3db/m3/src/x/instrument" 36 ) 37 38 type instrumentationContext struct { 39 opts Options 40 nowFn clock.NowFn 41 log *zap.Logger 42 start time.Time 43 span opentracing.Span 44 bootstrapDataDuration tally.Timer 45 bootstrapIndexDuration tally.Timer 46 profiler instrument.Profiler 47 logFields []zapcore.Field 48 } 49 50 func newInstrumentationContext( 51 opts Options, 52 nowFn clock.NowFn, 53 log *zap.Logger, 54 span opentracing.Span, 55 scope tally.Scope, 56 profiler instrument.Profiler, 57 ) *instrumentationContext { 58 return &instrumentationContext{ 59 opts: opts, 60 nowFn: nowFn, 61 log: log, 62 span: span, 63 profiler: profiler, 64 bootstrapDataDuration: scope.Timer("data-duration"), 65 bootstrapIndexDuration: scope.Timer("index-duration"), 66 logFields: []zapcore.Field{ 67 zap.Stringer("cachePolicy", opts.ResultOptions().SeriesCachePolicy()), 68 }, 69 } 70 } 71 72 const ( 73 dataProfile = "fs-data" 74 indexProfile = "fs-index" 75 ) 76 77 func (i *instrumentationContext) finish() { 78 i.span.Finish() 79 } 80 81 func (i *instrumentationContext) startCPUProfile(name string) { 82 err := i.profiler.StartCPUProfile(name) 83 if err != nil { 84 i.log.Error("unable to start cpu profile", zap.Error(err)) 85 } 86 } 87 88 func (i *instrumentationContext) stopCPUProfile() { 89 if err := i.profiler.StopCPUProfile(); err != nil { 90 i.log.Error("unable to stop cpu profile", zap.Error(err)) 91 } 92 } 93 94 func (i *instrumentationContext) writeHeapProfile(name string) { 95 err := i.profiler.WriteHeapProfile(name) 96 if err != nil { 97 i.log.Error("unable to write heap profile", zap.Error(err)) 98 } 99 } 100 101 func (i *instrumentationContext) bootstrapDataStarted() { 102 i.log.Info("bootstrapping time series data start", i.logFields...) 103 i.span.LogFields(opentracinglog.String("event", "bootstrap_data_start")) 104 i.start = i.nowFn() 105 i.startCPUProfile(dataProfile) 106 i.writeHeapProfile(dataProfile) 107 } 108 109 func (i *instrumentationContext) bootstrapDataCompleted() { 110 duration := i.nowFn().Sub(i.start) 111 i.bootstrapDataDuration.Record(duration) 112 i.log.Info("bootstrapping time series data success", 113 append(i.logFields, zap.Duration("took", duration))...) 114 i.span.LogFields(opentracinglog.String("event", "bootstrap_data_done")) 115 i.stopCPUProfile() 116 i.writeHeapProfile(dataProfile) 117 } 118 119 func (i *instrumentationContext) bootstrapIndexStarted() { 120 i.log.Info("bootstrapping index metadata start") 121 i.span.LogFields(opentracinglog.String("event", "bootstrap_index_start")) 122 i.start = i.nowFn() 123 i.startCPUProfile(indexProfile) 124 i.writeHeapProfile(indexProfile) 125 } 126 127 func (i *instrumentationContext) bootstrapIndexCompleted() { 128 duration := i.nowFn().Sub(i.start) 129 i.bootstrapIndexDuration.Record(duration) 130 i.log.Info("bootstrapping index metadata success", zap.Duration("took", duration)) 131 i.span.LogFields(opentracinglog.String("event", "bootstrap_index_done")) 132 i.stopCPUProfile() 133 i.writeHeapProfile(indexProfile) 134 } 135 136 type instrumentation struct { 137 opts Options 138 profiler instrument.Profiler 139 scope tally.Scope 140 log *zap.Logger 141 nowFn clock.NowFn 142 } 143 144 func newInstrumentation(opts Options, scope tally.Scope, iOpts instrument.Options) *instrumentation { 145 return &instrumentation{ 146 opts: opts, 147 profiler: iOpts.Profiler(), 148 scope: scope, 149 log: iOpts.Logger().With(zap.String("bootstrapper", "filesystem")), 150 nowFn: opts.ResultOptions().ClockOptions().NowFn(), 151 } 152 } 153 154 func (i *instrumentation) fsBootstrapperSourceReadStarted( 155 ctx context.Context, 156 ) *instrumentationContext { 157 _, span, _ := ctx.StartSampledTraceSpan(tracepoint.BootstrapperFilesystemSourceRead) 158 return newInstrumentationContext( 159 i.opts, 160 i.nowFn, 161 i.log, 162 span, 163 i.scope, 164 i.profiler, 165 ) 166 }