github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/event_system.go (about)

     1  package gateway
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/base64"
     6  	"errors"
     7  	"fmt"
     8  	"net/http"
     9  	"time"
    10  
    11  	"github.com/sirupsen/logrus"
    12  
    13  	circuit "github.com/TykTechnologies/circuitbreaker"
    14  	"github.com/TykTechnologies/tyk/apidef"
    15  	"github.com/TykTechnologies/tyk/config"
    16  )
    17  
    18  // The name for event handlers as defined in the API Definition JSON/BSON format
    19  const EH_LogHandler apidef.TykEventHandlerName = "eh_log_handler"
    20  
    21  // Register new event types here, the string is the code used to hook at the Api Deifnititon JSON/BSON level
    22  const (
    23  	EventQuotaExceeded        apidef.TykEvent = "QuotaExceeded"
    24  	EventRateLimitExceeded    apidef.TykEvent = "RatelimitExceeded"
    25  	EventAuthFailure          apidef.TykEvent = "AuthFailure"
    26  	EventKeyExpired           apidef.TykEvent = "KeyExpired"
    27  	EventVersionFailure       apidef.TykEvent = "VersionFailure"
    28  	EventOrgQuotaExceeded     apidef.TykEvent = "OrgQuotaExceeded"
    29  	EventOrgRateLimitExceeded apidef.TykEvent = "OrgRateLimitExceeded"
    30  	EventTriggerExceeded      apidef.TykEvent = "TriggerExceeded"
    31  	EventBreakerTriggered     apidef.TykEvent = "BreakerTriggered"
    32  	EventHOSTDOWN             apidef.TykEvent = "HostDown"
    33  	EventHOSTUP               apidef.TykEvent = "HostUp"
    34  	EventTokenCreated         apidef.TykEvent = "TokenCreated"
    35  	EventTokenUpdated         apidef.TykEvent = "TokenUpdated"
    36  	EventTokenDeleted         apidef.TykEvent = "TokenDeleted"
    37  )
    38  
    39  // EventMetaDefault is a standard embedded struct to be used with custom event metadata types, gives an interface for
    40  // easily extending event metadata objects
    41  type EventMetaDefault struct {
    42  	Message            string
    43  	OriginatingRequest string
    44  }
    45  
    46  type EventHostStatusMeta struct {
    47  	EventMetaDefault
    48  	HostInfo HostHealthReport
    49  }
    50  
    51  // EventKeyFailureMeta is the metadata structure for any failure related
    52  // to a key, such as quota or auth failures.
    53  type EventKeyFailureMeta struct {
    54  	EventMetaDefault
    55  	Path   string
    56  	Origin string
    57  	Key    string
    58  }
    59  
    60  // EventCurcuitBreakerMeta is the event status for a circuit breaker tripping
    61  type EventCurcuitBreakerMeta struct {
    62  	EventMetaDefault
    63  	Path         string
    64  	APIID        string
    65  	CircuitEvent circuit.BreakerEvent
    66  }
    67  
    68  // EventVersionFailureMeta is the metadata structure for an auth failure (EventKeyExpired)
    69  type EventVersionFailureMeta struct {
    70  	EventMetaDefault
    71  	Path   string
    72  	Origin string
    73  	Key    string
    74  	Reason string
    75  }
    76  
    77  type EventTriggerExceededMeta struct {
    78  	EventMetaDefault
    79  	OrgID           string `json:"org_id"`
    80  	Key             string `json:"key"`
    81  	TriggerLimit    int64  `json:"trigger_limit"`
    82  	UsagePercentage int64  `json:"usage_percentage"`
    83  }
    84  
    85  type EventTokenMeta struct {
    86  	EventMetaDefault
    87  	Org string
    88  	Key string
    89  }
    90  
    91  // EncodeRequestToEvent will write the request out in wire protocol and
    92  // encode it to base64 and store it in an Event object
    93  func EncodeRequestToEvent(r *http.Request) string {
    94  	var asBytes bytes.Buffer
    95  	r.Write(&asBytes)
    96  
    97  	return base64.StdEncoding.EncodeToString(asBytes.Bytes())
    98  }
    99  
   100  // EventHandlerByName is a convenience function to get event handler instances from an API Definition
   101  func EventHandlerByName(handlerConf apidef.EventHandlerTriggerConfig, spec *APISpec) (config.TykEventHandler, error) {
   102  
   103  	conf := handlerConf.HandlerMeta
   104  	switch handlerConf.Handler {
   105  	case EH_LogHandler:
   106  		h := &LogMessageEventHandler{}
   107  		err := h.Init(conf)
   108  		return h, err
   109  	case EH_WebHook:
   110  		h := &WebHookHandler{}
   111  		err := h.Init(conf)
   112  		return h, err
   113  	case EH_JSVMHandler:
   114  		// Load the globals and file here
   115  		if spec != nil {
   116  			h := &JSVMEventHandler{Spec: spec}
   117  			err := h.Init(conf)
   118  			if err == nil {
   119  				GlobalEventsJSVM.LoadJSPaths([]string{conf["path"].(string)}, "")
   120  			}
   121  			return h, err
   122  		}
   123  	case EH_CoProcessHandler:
   124  		if spec != nil {
   125  			dispatcher := loadedDrivers[spec.CustomMiddleware.Driver]
   126  			if dispatcher == nil {
   127  				return nil, errors.New("no plugin driver is available")
   128  			}
   129  			h := &CoProcessEventHandler{}
   130  			h.Spec = spec
   131  			err := h.Init(conf)
   132  			return h, err
   133  		}
   134  	}
   135  
   136  	return nil, errors.New("Handler not found")
   137  }
   138  
   139  func fireEvent(name apidef.TykEvent, meta interface{}, handlers map[apidef.TykEvent][]config.TykEventHandler) {
   140  	log.Debug("EVENT FIRED: ", name)
   141  	if handlers, e := handlers[name]; e {
   142  		log.Debugf("FOUND %d EVENT HANDLERS", len(handlers))
   143  		eventMessage := config.EventMessage{
   144  			Meta:      meta,
   145  			Type:      name,
   146  			TimeStamp: time.Now().Local().String(),
   147  		}
   148  		for _, handler := range handlers {
   149  			log.Debug("FIRING HANDLER: ", handler)
   150  			go handler.HandleEvent(eventMessage)
   151  		}
   152  	}
   153  }
   154  
   155  func (s *APISpec) FireEvent(name apidef.TykEvent, meta interface{}) {
   156  	fireEvent(name, meta, s.EventPaths)
   157  }
   158  
   159  func FireSystemEvent(name apidef.TykEvent, meta interface{}) {
   160  	fireEvent(name, meta, config.Global().GetEventTriggers())
   161  }
   162  
   163  // LogMessageEventHandler is a sample Event Handler
   164  type LogMessageEventHandler struct {
   165  	prefix string
   166  	logger *logrus.Logger
   167  }
   168  
   169  // New enables the intitialisation of event handler instances when they are created on ApiSpec creation
   170  func (l *LogMessageEventHandler) Init(handlerConf interface{}) error {
   171  	conf := handlerConf.(map[string]interface{})
   172  	l.prefix = conf["prefix"].(string)
   173  	l.logger = log
   174  	if isRunningTests() {
   175  		logger, ok := conf["logger"]
   176  		if ok {
   177  			l.logger = logger.(*logrus.Logger)
   178  		}
   179  	}
   180  	return nil
   181  }
   182  
   183  // HandleEvent will be fired when the event handler instance is found in an APISpec EventPaths object during a request chain
   184  func (l *LogMessageEventHandler) HandleEvent(em config.EventMessage) {
   185  	logMsg := l.prefix + ":" + string(em.Type)
   186  
   187  	// We can handle specific event types easily
   188  	if em.Type == EventQuotaExceeded {
   189  		msgConf := em.Meta.(EventKeyFailureMeta)
   190  		logMsg = logMsg + ":" + msgConf.Key + ":" + msgConf.Origin + ":" + msgConf.Path
   191  	}
   192  
   193  	if em.Type == EventBreakerTriggered {
   194  		msgConf := em.Meta.(EventCurcuitBreakerMeta)
   195  		logMsg = logMsg + ":" + msgConf.APIID + ":" + msgConf.Path + ": [STATUS] " + fmt.Sprint(msgConf.CircuitEvent)
   196  	}
   197  
   198  	l.logger.Warning(logMsg)
   199  }
   200  
   201  func initGenericEventHandlers(conf *config.Config) {
   202  	handlers := make(map[apidef.TykEvent][]config.TykEventHandler)
   203  	for eventName, eventHandlerConfs := range conf.EventHandlers.Events {
   204  		log.Debug("FOUND EVENTS TO INIT")
   205  		for _, handlerConf := range eventHandlerConfs {
   206  			log.Debug("CREATING EVENT HANDLERS")
   207  			eventHandlerInstance, err := EventHandlerByName(handlerConf, nil)
   208  
   209  			if err != nil {
   210  				log.Error("Failed to init event handler: ", err)
   211  			} else {
   212  				log.Debug("Init Event Handler: ", eventName)
   213  				handlers[eventName] = append(handlers[eventName], eventHandlerInstance)
   214  			}
   215  
   216  		}
   217  	}
   218  	conf.SetEventTriggers(handlers)
   219  }