github.com/Rookout/GoSDK@v0.1.48/pkg/com_ws/output_ws.go (about) 1 package com_ws 2 3 import ( 4 "io" 5 "sync" 6 "sync/atomic" 7 "time" 8 9 "github.com/Rookout/GoSDK/pkg/common" 10 "github.com/Rookout/GoSDK/pkg/config" 11 "github.com/Rookout/GoSDK/pkg/logger" 12 "github.com/Rookout/GoSDK/pkg/processor/namespaces" 13 pb "github.com/Rookout/GoSDK/pkg/protobuf" 14 "github.com/Rookout/GoSDK/pkg/rookoutErrors" 15 "github.com/Rookout/GoSDK/pkg/types" 16 "github.com/Rookout/GoSDK/pkg/utils" 17 "google.golang.org/protobuf/types/known/timestamppb" 18 ) 19 20 type Output interface { 21 SetAgentID(agentID string) 22 23 SendUserMessage(augID types.AugID, messageID string, arguments namespaces.Namespace) 24 SendRuleStatus(augID types.AugID, active string, errIn rookoutErrors.RookoutError) error 25 SendWarning(augID types.AugID, err rookoutErrors.RookoutError) error 26 SendError(augID types.AugID, err rookoutErrors.RookoutError) error 27 SendOutputQueueFullWarning(augID types.AugID) 28 29 SetAgentCom(agentCom AgentCom) 30 31 StopSendingMessages() 32 } 33 34 type outputWs struct { 35 agentID string 36 agentCom AgentCom 37 closed atomic.Value 38 skippedAugIDs *SyncSet 39 } 40 41 func NewOutputWs() *outputWs { 42 o := &outputWs{ 43 closed: atomic.Value{}, 44 skippedAugIDs: newSyncSet(), 45 } 46 o.closed.Store(false) 47 return o 48 } 49 50 func (d *outputWs) SetAgentCom(agentCom AgentCom) { 51 d.agentCom = agentCom 52 } 53 54 func (d *outputWs) SetAgentID(agentID string) { 55 d.agentID = agentID 56 } 57 58 func (d *outputWs) SendUserMessage(augID types.AugID, messageID string, arguments namespaces.Namespace) { 59 utils.CreateGoroutine(func() { 60 defer func() { 61 if closer, ok := arguments.(io.Closer); ok { 62 _ = closer.Close() 63 } 64 }() 65 66 err := d.sendUserMessage(augID, messageID, arguments) 67 if err != nil { 68 logger.Logger().WithError(err).Warningf("Unable to send user message, aug id: %s", augID) 69 } 70 }) 71 } 72 73 func (d *outputWs) sendUserMessage(augID types.AugID, messageID string, arguments namespaces.Namespace) error { 74 if d.closed.Load().(bool) { 75 return nil 76 } 77 78 msg := &pb.AugReportMessage{ 79 AgentId: d.agentID, 80 AugID: augID, 81 ReportID: messageID, 82 } 83 if config.OutputWsConfig().ProtobufVersion2 { 84 serializer := namespaces.NewNamespaceSerializer2(arguments, true) 85 msg.Arguments2 = serializer.Variant2 86 msg.StringsCache = serializer.StringCache 87 } else { 88 serializer := namespaces.NewNamespaceSerializer(arguments, true) 89 msg.Arguments = serializer.Variant 90 } 91 buf, err := common.WrapMsgInEnvelope(msg) 92 if err != nil { 93 return err 94 } 95 96 rookoutErr := d.agentCom.Send(buf) 97 if rookoutErr != nil && rookoutErr.GetType() == "RookOutputQueueFull" { 98 d.SendOutputQueueFullWarning(augID) 99 return rookoutErr 100 } 101 102 d.skippedAugIDs.Remove(augID) 103 return nil 104 } 105 106 func (d *outputWs) SendRuleStatus(augID types.AugID, active string, errIn rookoutErrors.RookoutError) error { 107 if d.closed.Load().(bool) { 108 return nil 109 } 110 111 if active == "Deleted" { 112 d.skippedAugIDs.Remove(augID) 113 } 114 115 stat := &pb.RuleStatusMessage{ 116 AgentId: d.agentID, 117 RuleId: augID, 118 Active: active, 119 } 120 if errIn != nil { 121 serializer := namespaces.NewNamespaceSerializer(namespaces.NewGoObjectNamespace(errIn), true) 122 stat.Error = serializer.GetErrorValue() 123 } 124 125 buf, err := common.WrapMsgInEnvelope(stat) 126 if err != nil { 127 return err 128 } 129 return d.agentCom.Send(buf) 130 } 131 132 func (d *outputWs) SendWarning(augID types.AugID, err rookoutErrors.RookoutError) error { 133 return d.SendRuleStatus(augID, "Warning", err) 134 } 135 136 func (d *outputWs) SendError(augID types.AugID, err rookoutErrors.RookoutError) error { 137 return d.SendRuleStatus(augID, "Error", err) 138 } 139 140 func (d *outputWs) SendLogMessage(level pb.LogMessage_LogLevel, time time.Time, filename string, lineno int, text string, arguments map[string]interface{}) error { 141 if d.closed.Load().(bool) || d.agentCom == nil { 142 return nil 143 } 144 145 argumentsNamespace := namespaces.NewEmptyContainerNamespace() 146 parametersNamespace := namespaces.NewEmptyContainerNamespace() 147 for k, v := range arguments { 148 if v == nil { 149 continue 150 } 151 152 if k == "error" { 153 _ = argumentsNamespace.WriteAttribute("exc", namespaces.NewGoObjectNamespace(v)) 154 } else { 155 _ = parametersNamespace.WriteAttribute(k, namespaces.NewGoObjectNamespace(v)) 156 } 157 } 158 _ = argumentsNamespace.WriteAttribute("args", parametersNamespace) 159 serializer := namespaces.NewNamespaceSerializer(argumentsNamespace, false) 160 161 timestamp := timestamppb.New(time) 162 msg := &pb.LogMessage{ 163 Timestamp: timestamp, 164 AgentId: d.agentID, 165 Level: level, 166 Filename: filename, 167 Line: uint32(lineno), 168 Text: text, 169 FormattedMessage: text, 170 Arguments: []*pb.Variant{serializer.Variant}, 171 LegacyArguments: serializer.Variant, 172 } 173 buf, err := common.WrapMsgInEnvelope(msg) 174 if err != nil { 175 return err 176 } 177 return d.agentCom.Send(buf) 178 } 179 180 func (d *outputWs) StopSendingMessages() { 181 d.closed.Store(true) 182 } 183 184 func (d *outputWs) SendOutputQueueFullWarning(augID types.AugID) { 185 if d.skippedAugIDs.Contains(augID) { 186 return 187 } 188 189 d.skippedAugIDs.Add(augID) 190 _ = d.SendRuleStatus(augID, "Warning", rookoutErrors.NewRookOutputQueueFull()) 191 logger.Logger().Warning("Skipping aug (" + augID + ") execution because the queue is full") 192 } 193 194 type SyncSet struct { 195 internalMap map[types.AugID]struct{} 196 lock sync.Mutex 197 } 198 199 func newSyncSet() *SyncSet { 200 return &SyncSet{internalMap: make(map[types.AugID]struct{})} 201 } 202 203 func (s *SyncSet) Add(value interface{}) { 204 s.lock.Lock() 205 defer s.lock.Unlock() 206 207 s.internalMap[value.(types.AugID)] = struct{}{} 208 } 209 210 func (s *SyncSet) Remove(value interface{}) { 211 s.lock.Lock() 212 defer s.lock.Unlock() 213 214 delete(s.internalMap, value.(types.AugID)) 215 } 216 217 func (s *SyncSet) Contains(value interface{}) bool { 218 s.lock.Lock() 219 defer s.lock.Unlock() 220 221 _, ok := s.internalMap[value.(types.AugID)] 222 return ok 223 }