package rules import ( "bytes" "encoding/json" "errors" "fmt" "iwarma.ru/console/correlator/events" "log/syslog" "strconv" "text/template" "github.com/spf13/viper" "iwarma.ru/console/correlator/config" log "github.com/sirupsen/logrus" ) const ( SyslogProtoTcp = "tcp" SyslogProtoUdp = "udp" SyslogActionType = "syslog" ) // SyslogAction Send record with syslog to selected host type SyslogAction struct { Host string Port int Proto string Name string Template string writer *syslog.Writer bodyTemplate *template.Template } func (action SyslogAction) GetType() string { return SyslogActionType } func (action SyslogAction) Perform(events *[]*events.Event) error { contextLogger := log.WithFields(log.Fields{"type": SyslogActionType, "event_count": len(*events)}) contextLogger.Debug("Start action") defer contextLogger.Debug("End action") if events == nil { contextLogger.Error("Nil events provided") return errors.New("nil events provided") } // Create connection to syslog server if action.writer == nil { if action.Proto != SyslogProtoTcp && action.Proto != SyslogProtoUdp { return fmt.Errorf("bad syslog protocol %v", action.Proto) } writer, err := syslog.Dial(action.Proto, fmt.Sprintf("%v:%v", action.Host, action.Port), syslog.LOG_LOCAL0, viper.GetString(config.SyslogTag)) if err != nil { return err } action.writer = writer } // Create template if action.bodyTemplate == nil { bodyTemplate, err := template.New("Action").Parse(action.Template) if err != nil { return err } action.bodyTemplate = bodyTemplate } // Send messages for _, cur := range *events { var buf bytes.Buffer err := action.bodyTemplate.Execute(&buf, *cur) if err != nil { return err } err = action.writer.Info(buf.String()) if err != nil { return err } } return nil } func (action SyslogAction) MarshalJSON() ([]byte, error) { return json.Marshal(struct { CurType string `json:"type"` Host string `json:"host"` Port string `json:"port"` Proto string `json:"protocol"` Name string `json:"name"` Format string `json:"format"` Template string `json:"template"` }{ CurType: SyslogActionType, Host: action.Host, Port: strconv.Itoa(action.Port), Proto: action.Proto, Name: action.Name, Format: "", Template: action.Template, }) } func (action *SyslogAction) UnmarshalJSON(b []byte) error { cur := struct { CurType string `json:"type"` Host string `json:"host"` Port string `json:"port"` Proto string `json:"protocol"` Name string `json:"name"` Format string `json:"format"` Template string `json:"template"` }{} err := json.Unmarshal(b, &cur) if err != nil { return err } if cur.CurType != SyslogActionType { return fmt.Errorf("bad action type. Expect http, got %s", cur.CurType) } action.Host = cur.Host action.Port, err = strconv.Atoi(cur.Port) if err != nil { return fmt.Errorf("can't parse port: %v", cur.Port) } action.Proto = cur.Proto action.Name = cur.Name action.Template = cur.Template return nil } func (action *SyslogAction) ParseInterface(v interface{}) error { m, ok := v.(map[string]interface{}) if !ok { return fmt.Errorf("can't parse %v from %T", v, v) } action.Host, ok = m["host"].(string) if !ok { return errors.New("can't get host") } // Port can bee int (float64) or string if port, ok := m["port"].(float64); ok { action.Port = int(port) } else if port, ok := m["port"].(string); ok { cur, err := strconv.Atoi(port) if err != nil { return fmt.Errorf("bad port string: %v", port) } action.Port = cur } else { return fmt.Errorf("bad port type: %T with value %v", port, port) } action.Proto, ok = m["protocol"].(string) if !ok { return errors.New("can't get protocol") } action.Name, ok = m["name"].(string) if !ok { return errors.New("can't get name") } // Template can be in data or template if action.Template, ok = m["data"].(string); !ok { if action.Template, ok = m["template"].(string); !ok { return errors.New("can't get template") } } return nil }