Changeset 178 in code for trunk/upstream.go


Ignore:
Timestamp:
Mar 27, 2020, 11:07:20 PM (5 years ago)
Author:
delthas
Message:

Add support for bouncer logs

Add bouncer logs, in a network/channel/date.log format, in a similar
manner to ZNC log module. PRIVMSG, JOIN, PART, QUIT, MODE are logged.

Add a config directive for the logs file, including a way to disable
them entirely.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/upstream.go

    r177 r178  
    88        "io"
    99        "net"
     10        "os"
     11        "path/filepath"
    1012        "strconv"
    1113        "strings"
     
    6466        // access is synchronized with user.pendingLISTsLock
    6567        pendingLISTDownstreamSet map[uint64]struct{}
     68
     69        logs map[string]entityLog
     70}
     71
     72type entityLog struct {
     73        name string
     74        file *os.File
    6675}
    6776
     
    98107                availableMemberships:     stdMemberships,
    99108                pendingLISTDownstreamSet: make(map[uint64]struct{}),
     109                logs:                     make(map[string]entityLog),
    100110        }
    101111
     
    142152        }
    143153        close(uc.closed)
    144 
     154        for _, log := range uc.logs {
     155                log.file.Close()
     156        }
    145157        uc.endPendingLists(true)
    146158        return nil
     
    313325                                return err
    314326                        }
     327
     328                        target := nick
     329                        if nick == uc.nick {
     330                                target = msg.Prefix.Name
     331                        }
     332                        uc.AppendLog(target, "<%s> %s", msg.Prefix.Name, text)
    315333
    316334                        uc.forEachDownstream(func(dc *downstreamConn) {
     
    617635                                delete(ch.Members, msg.Prefix.Name)
    618636                                ch.Members[newNick] = membership
     637                                uc.AppendLog(ch.Name, "*** %s is now known as %s", msg.Prefix.Name, newNick)
    619638                        }
    620639                }
     
    660679                        }
    661680
     681                        uc.AppendLog(ch, "*** Joins: %s (%s@%s)", msg.Prefix.Name, msg.Prefix.User, msg.Prefix.Host)
     682
    662683                        uc.forEachDownstream(func(dc *downstreamConn) {
    663684                                dc.SendMessage(&irc.Message{
     
    676697                if err := parseMessageParams(msg, &channels); err != nil {
    677698                        return err
     699                }
     700
     701                var reason string
     702                if len(msg.Params) > 1 {
     703                        reason = msg.Params[1]
    678704                }
    679705
     
    690716                        }
    691717
     718                        uc.AppendLog(ch, "*** Parts: %s (%s@%s) (%s)", msg.Prefix.Name, msg.Prefix.User, msg.Prefix.Host, reason)
     719
    692720                        uc.forEachDownstream(func(dc *downstreamConn) {
    693721                                dc.SendMessage(&irc.Message{
     
    724752                }
    725753
     754                uc.AppendLog(channel, "*** %s was kicked by %s (%s)", user, msg.Prefix.Name, reason)
     755
    726756                uc.forEachDownstream(func(dc *downstreamConn) {
    727757                        params := []string{dc.marshalChannel(uc, channel), dc.marshalNick(uc, user)}
     
    740770                }
    741771
     772                var reason string
     773                if len(msg.Params) > 0 {
     774                        reason = msg.Params[0]
     775                }
     776
    742777                if msg.Prefix.Name == uc.nick {
    743778                        uc.logger.Printf("quit")
     
    745780
    746781                for _, ch := range uc.channels {
    747                         delete(ch.Members, msg.Prefix.Name)
     782                        if _, ok := ch.Members[msg.Prefix.Name]; ok {
     783                                delete(ch.Members, msg.Prefix.Name)
     784
     785                                uc.AppendLog(ch.Name, "*** Quits: %s (%s@%s) (%s)", msg.Prefix.Name, msg.Prefix.User, msg.Prefix.Host, reason)
     786                        }
    748787                }
    749788
     
    819858                                }
    820859                        }
     860
     861                        modeMsg := modeStr
     862                        for _, v := range msg.Params[2:] {
     863                                modeMsg += " " + v
     864                        }
     865                        uc.AppendLog(ch.Name, "*** %s sets mode: %s", msg.Prefix.Name, modeMsg)
    821866
    822867                        uc.forEachDownstream(func(dc *downstreamConn) {
     
    11531198                }
    11541199
    1155                 var nick string
    1156                 if err := parseMessageParams(msg, &nick, nil); err != nil {
     1200                var nick, text string
     1201                if err := parseMessageParams(msg, &nick, &text); err != nil {
    11571202                        return err
    11581203                }
     
    11661211                        break
    11671212                }
     1213
     1214                target := nick
     1215                if nick == uc.nick {
     1216                        target = msg.Prefix.Name
     1217                }
     1218                uc.AppendLog(target, "<%s> %s", msg.Prefix.Name, text)
    11681219
    11691220                uc.network.ring.Produce(msg)
     
    13641415        uc.SendMessage(msg)
    13651416}
     1417
     1418// TODO: handle moving logs when a network name changes, when support for this is added
     1419func (uc *upstreamConn) AppendLog(entity string, format string, a ...interface{}) {
     1420        if uc.srv.LogPath == "" {
     1421                return
     1422        }
     1423        // TODO: enforce maximum open file handles (LRU cache of file handles)
     1424        // TODO: handle non-monotonic clock behaviour
     1425        now := time.Now()
     1426        year, month, day := now.Date()
     1427        name := fmt.Sprintf("%04d-%02d-%02d.log", year, month, day)
     1428        log, ok := uc.logs[entity]
     1429        if !ok || log.name != name {
     1430                if ok {
     1431                        log.file.Close()
     1432                        delete(uc.logs, entity)
     1433                }
     1434                // TODO: handle/forbid network/entity names with illegal path characters
     1435                dir := filepath.Join(uc.srv.LogPath, uc.user.Username, uc.network.Name, entity)
     1436                if err := os.MkdirAll(dir, 0600); err != nil {
     1437                        uc.logger.Printf("failed to log message: could not create logs directory %q: %v", dir, err)
     1438                        return
     1439                }
     1440                path := filepath.Join(dir, name)
     1441                f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
     1442                if err != nil {
     1443                        uc.logger.Printf("failed to log message: could not open or create log file %q: %v", path, err)
     1444                        return
     1445                }
     1446                log = entityLog{
     1447                        name: name,
     1448                        file: f,
     1449                }
     1450                uc.logs[entity] = log
     1451        }
     1452
     1453        format = "[%02d:%02d:%02d] " + format + "\n"
     1454        args := []interface{}{now.Hour(), now.Minute(), now.Second()}
     1455        args = append(args, a...)
     1456
     1457        if _, err := fmt.Fprintf(log.file, format, args...); err != nil {
     1458                uc.logger.Printf("failed to log message to %q: %v", log.name, err)
     1459        }
     1460}
Note: See TracChangeset for help on using the changeset viewer.