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 }