github.com/Rookout/GoSDK@v0.1.48/pkg/services/instrumentation/instrumentation_service.go (about) 1 package instrumentation 2 3 import ( 4 "strings" 5 "sync" 6 "time" 7 8 "github.com/Rookout/GoSDK/pkg/augs/locations" 9 "github.com/Rookout/GoSDK/pkg/locations_set" 10 "github.com/Rookout/GoSDK/pkg/logger" 11 "github.com/Rookout/GoSDK/pkg/rookoutErrors" 12 "github.com/Rookout/GoSDK/pkg/services/instrumentation/callback" 13 "github.com/Rookout/GoSDK/pkg/types" 14 "github.com/pkg/errors" 15 ) 16 17 const staleBreakpointClearInterval = 10 * time.Second 18 19 type InstrumentationService struct { 20 processManager *ProcessManager 21 22 locations *locations_set.LocationsSet 23 staleBreakpointsGC *ZombieCollector 24 instrumentationLock *sync.Mutex 25 26 breakpointFailedCounter uint64 27 } 28 29 func NewInstrumentationService(breakpointMonitorInterval time.Duration) (*InstrumentationService, rookoutErrors.RookoutError) { 30 locationsSet := locations_set.NewLocationsSet() 31 callback.SetLocationsSet(locationsSet) 32 33 processManager, rookErr := NewProcessManager(locationsSet, breakpointMonitorInterval) 34 if rookErr != nil { 35 return nil, rookErr 36 } 37 38 instrumentationLock := &sync.Mutex{} 39 bpGC := NewZombieCollector(staleBreakpointClearInterval, locationsSet, instrumentationLock, processManager.EraseBreakpoint) 40 bpGC.Start() 41 return &InstrumentationService{locations: locationsSet, staleBreakpointsGC: bpGC, instrumentationLock: instrumentationLock, processManager: processManager}, nil 42 } 43 44 func funcForInit() { 45 _ = 3 46 } 47 48 func (i *InstrumentationService) AddAug(location locations.Location) { 49 i.instrumentationLock.Lock() 50 defer i.instrumentationLock.Unlock() 51 52 i.addAug(location) 53 } 54 55 56 func (i *InstrumentationService) addAug(location locations.Location) { 57 if !strings.HasSuffix(location.GetFileName(), ".go") { 58 return 59 } 60 61 logger.Logger().Debugf("Attempting to add aug (id=%s) on file %s line %d", 62 location.GetAugID(), location.GetFileName(), location.GetLineno()) 63 64 if err := location.SetPending(); err != nil { 65 logger.Logger().WithError(err).Errorf("Unable to set status of location %s to pending", location.GetAugID()) 66 } 67 68 if rookErr := i.setBreakpoint(location); rookErr != nil { 69 logger.Logger().WithError(rookErr).Errorf("Failed to add aug: %s", location.GetAugID()) 70 err := location.SetError(rookErr) 71 if err != nil { 72 logger.Logger().WithError(err).Errorf("Unable to set status of location %s to error", location.GetAugID()) 73 } 74 return 75 } 76 77 if err := location.SetActive(); err != nil { 78 logger.Logger().WithError(err).Errorf("Unable to set status of location %s to active", location.GetAugID()) 79 } 80 } 81 82 func (i *InstrumentationService) setBreakpoint(location locations.Location) rookoutErrors.RookoutError { 83 filename := location.GetFileName() 84 lineno := location.GetLineno() 85 86 breakpoint, rookErr := i.processManager.WriteBreakpoint(filename, lineno) 87 if rookErr != nil { 88 return rookErr 89 } 90 91 i.locations.AddLocation(location, breakpoint) 92 logger.Logger().Infof("Successfully placed breakpoint on file %s line %d", filename, lineno) 93 94 return nil 95 } 96 97 func (i *InstrumentationService) RemoveAug(augID types.AugID) error { 98 i.instrumentationLock.Lock() 99 defer i.instrumentationLock.Unlock() 100 101 return i.removeAug(augID) 102 } 103 104 105 func (i *InstrumentationService) removeAug(augID types.AugID) error { 106 logger.Logger().Debugf("Attempting to remove aug %s", augID) 107 bp, exists := i.locations.FindBreakpointByAugID(augID) 108 if !exists { 109 return errors.Errorf("no aug found with id %s", augID) 110 } 111 112 i.locations.RemoveLocation(augID) 113 shouldClear, err := i.locations.ShouldClearBreakpoint(bp) 114 if err != nil { 115 return err 116 } 117 if shouldClear { 118 logger.Logger().Debugf("Clearing breakpoint (name=%s) on file %s line %d", bp.Name, bp.File, bp.Line) 119 err = i.processManager.EraseBreakpoint(bp) 120 if err != nil { 121 return err 122 } 123 i.locations.RemoveBreakpoint(bp) 124 } 125 logger.Logger().Infof("Successfully removed aug ID %s", augID) 126 return nil 127 } 128 129 func (i *InstrumentationService) ReplaceAllRules(newAugs map[types.AugID]locations.Location) error { 130 i.instrumentationLock.Lock() 131 defer i.instrumentationLock.Unlock() 132 133 var augIDsToRemove []types.AugID 134 for _, location := range i.locations.Locations() { 135 if _, exists := newAugs[location.GetAug().GetAugID()]; exists { 136 137 delete(newAugs, location.GetAug().GetAugID()) 138 } else { 139 augIDsToRemove = append(augIDsToRemove, location.GetAug().GetAugID()) 140 } 141 } 142 143 for _, augID := range augIDsToRemove { 144 err := i.removeAug(augID) 145 if err != nil { 146 logger.Logger().WithError(err).Errorf("Failed to clear aug %s", augID) 147 148 continue 149 } 150 } 151 for _, aug := range newAugs { 152 i.addAug(aug) 153 } 154 155 return nil 156 } 157 158 func (i *InstrumentationService) ClearAugs() { 159 i.instrumentationLock.Lock() 160 defer i.instrumentationLock.Unlock() 161 162 for _, loc := range i.locations.Locations() { 163 if err := i.removeAug(loc.GetAugID()); err != nil { 164 logger.Logger().WithError(err).Errorf("Unable to remove aug: %s\n", loc.GetAugID()) 165 } 166 } 167 } 168 169 func (i *InstrumentationService) Stop() { 170 if i.staleBreakpointsGC != nil { 171 i.staleBreakpointsGC.Stop() 172 } 173 174 err := i.processManager.Clean() 175 if err != nil { 176 logger.Logger().WithError(err).Errorln("Failed to clean process manager") 177 } 178 }