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  }