old_console/correlator/rules/action_syslog.go
2024-11-02 14:12:45 +03:00

184 lines
4.1 KiB
Go

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
}