package nsa import ( "database/sql" "encoding/json" "errors" "fmt" "os" "strings" ) var database *sql.DB var eventmap = make(map[string]int) type Logger struct { ip string } func NewLogger(ip string) *Logger { return &Logger{ ip: ip, } } func (l *Logger) getEventID(event string) int { evID, ok := eventmap[event] if !ok { logErr("Event %s does not exist.", event) return 0 } return evID } func (l *Logger) getJSON(data interface{}) string { jsonStr, err := json.Marshal(data) if err != nil { logErr("%v", err) return "" } return string(jsonStr) } func (l *Logger) insertEvent(id int, data string) { if database == nil { return } _, err := database.Exec( "INSERT INTO nsa.events (type, data, client_ip) VALUES ($1, $2, $3);", id, data, l.ip) if err != nil { logErr("%v", err) } } func (l *Logger) Log(event string, data interface{}) { if database == nil { return } go func() { id := l.getEventID(event) if id == 0 { return } d := l.getJSON(data) if d == "" { return } l.insertEvent(id, d) }() } func logErr(msg string, params ...interface{}) { fmt.Fprintf( os.Stderr, "NSA: Error: %v\n", fmt.Sprintf(msg, params...)) } func Init(db *sql.DB) error { err := db.Ping() if err != nil { return err } database = db return nil } func SetEvents(events []string) error { if database == nil { return errors.New("not initialized") } rows, err := database.Query("SELECT id, name FROM nsa.event_types;") if err != nil { return err } defer rows.Close() for rows.Next() { var id int var name string rows.Scan(&id, &name) eventmap[name] = id } newEvents := []string{} params := "" paramNum := 1 for _, event := range events { e := strings.ToUpper(event) if _, ok := eventmap[event]; ok { continue } newEvents = append(newEvents, e) params += fmt.Sprintf("($%d),", paramNum) paramNum++ } if len(newEvents) > 0 { params = params[0 : len(params)-1] values := []interface{}{} for _, event := range newEvents { values = append(values, event) } rows, err = database.Query( fmt.Sprintf( "INSERT INTO nsa.event_types (name) VALUES %s RETURNING id;", params), values...) if err != nil { return err } defer rows.Close() i := 0 for rows.Next() { var id int rows.Scan(&id) eventmap[newEvents[i]] = id i++ } } return nil }