X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=src%2Flog.go;h=7953a0227afe14836cb878ccbe10fa4020ad8539;hb=0367cce2741e1ce6a89a49fd5c4e9df6005c9744;hp=b83db340170668ead8821ac96f67ea2903e8ebee;hpb=dd887c15fa21071a2f4931f7248e10c4ab1029d2;p=nncp.git diff --git a/src/log.go b/src/log.go index b83db34..7953a02 100644 --- a/src/log.go +++ b/src/log.go @@ -1,6 +1,6 @@ /* NNCP -- Node to Node copy, utilities for store-and-forward data exchange -Copyright (C) 2016-2019 Sergey Matveev +Copyright (C) 2016-2022 Sergey Matveev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,47 +18,79 @@ along with this program. If not, see . package nncp import ( + "bytes" "fmt" "os" - "sort" - "strings" + "sync" "time" + "go.cypherpunks.ru/recfile" "golang.org/x/sys/unix" ) -type LogLevel string +const LogFdPrefix = "FD:" -type SDS map[string]interface{} +var ( + LogFd *os.File + LogFdLock sync.Mutex +) -func sdFmt(who string, sds SDS) string { - keys := make([]string, 0, len(sds)) - for k, _ := range sds { - keys = append(keys, k) - } - sort.Strings(keys) - result := make([]string, 0, 1+len(keys)) - result = append(result, "["+who) - for _, k := range keys { - result = append(result, fmt.Sprintf(`%s="%s"`, k, sds[k])) - } - return strings.Join(result, " ") + "]" +type LE struct { + K string + V interface{} } +type LEs []LE -func msgFmt(level LogLevel, who string, sds SDS, msg string) string { - result := fmt.Sprintf( - "%s %s %s", - level, - time.Now().UTC().Format(time.RFC3339Nano), - sdFmt(who, sds), - ) - if len(msg) > 0 { - result += " " + msg +func (les LEs) Rec() string { + b := bytes.NewBuffer(make([]byte, 0, 1<<10)) + w := recfile.NewWriter(b) + _, err := w.RecordStart() + if err != nil { + panic(err) } - return result + "\n" + _, err = w.WriteFields(recfile.Field{ + Name: "When", + Value: time.Now().UTC().Format(time.RFC3339Nano), + }) + if err != nil { + panic(err) + } + for _, le := range les { + switch v := le.V.(type) { + case int, int8, uint8, int64, uint64: + _, err = w.WriteFields(recfile.Field{ + Name: le.K, + Value: fmt.Sprintf("%d", v), + }) + case bool: + _, err = w.WriteFields(recfile.Field{ + Name: le.K, + Value: fmt.Sprintf("%v", v), + }) + case []string: + if len(v) > 0 { + _, err = w.WriteFieldMultiline(le.K, v) + } + default: + _, err = w.WriteFields(recfile.Field{ + Name: le.K, + Value: fmt.Sprintf("%s", v), + }) + } + if err != nil { + panic(err) + } + } + return b.String() } -func (ctx *Ctx) Log(msg string) { +func (ctx *Ctx) Log(rec string) { + if LogFd != nil { + LogFdLock.Lock() + LogFd.WriteString(rec) + LogFdLock.Unlock() + return + } fdLock, err := os.OpenFile( ctx.LogPath+".lock", os.O_CREATE|os.O_WRONLY, @@ -68,6 +100,7 @@ func (ctx *Ctx) Log(msg string) { fmt.Fprintln(os.Stderr, "Can not open lock for log:", err) return } + defer fdLock.Close() fdLockFd := int(fdLock.Fd()) err = unix.Flock(fdLockFd, unix.LOCK_EX) if err != nil { @@ -84,47 +117,41 @@ func (ctx *Ctx) Log(msg string) { fmt.Fprintln(os.Stderr, "Can not open log:", err) return } - fd.WriteString(msg) + fd.WriteString(rec) fd.Close() } -func (ctx *Ctx) LogD(who string, sds SDS, msg string) { +func (ctx *Ctx) LogD(who string, les LEs, msg func(LEs) string) { if !ctx.Debug { return } - fmt.Fprint(os.Stderr, msgFmt(LogLevel("D"), who, sds, msg)) + les = append(LEs{{"Debug", true}, {"Who", who}}, les...) + les = append(les, LE{"Msg", msg(les)}) + fmt.Fprint(os.Stderr, les.Rec()) } -func (ctx *Ctx) LogI(who string, sds SDS, msg string) { - msg = msgFmt(LogLevel("I"), who, sds, msg) - if !ctx.Quiet { - fmt.Fprintln(os.Stderr, ctx.Humanize(msg)) +func (ctx *Ctx) LogI(who string, les LEs, msg func(LEs) string) { + les = append(LEs{{"Who", who}}, les...) + les = append(les, LE{"Msg", msg(les)}) + rec := les.Rec() + if ctx.Debug { + fmt.Fprint(os.Stderr, rec) } - ctx.Log(msg) -} - -func (ctx *Ctx) LogP(who string, sds SDS, msg string) { if !ctx.Quiet { - fmt.Fprintln(os.Stderr, ctx.Humanize(msgFmt(LogLevel("P"), who, sds, msg))) + fmt.Fprintln(os.Stderr, ctx.HumanizeRec(rec)) } + ctx.Log(rec) } -func (ctx *Ctx) LogE(who string, sds SDS, msg string) { - msg = msgFmt(LogLevel("E"), who, sds, msg) - if len(msg) > 2048 { - msg = msg[:2048] +func (ctx *Ctx) LogE(who string, les LEs, err error, msg func(LEs) string) { + les = append(LEs{{"Err", err.Error()}, {"Who", who}}, les...) + les = append(les, LE{"Msg", msg(les)}) + rec := les.Rec() + if ctx.Debug { + fmt.Fprint(os.Stderr, rec) } - fmt.Fprintln(os.Stderr, ctx.Humanize(msg)) - ctx.Log(msg) -} - -func SdsAdd(sds, add SDS) SDS { - neu := SDS{} - for k, v := range sds { - neu[k] = v - } - for k, v := range add { - neu[k] = v + if !ctx.Quiet { + fmt.Fprintln(os.Stderr, ctx.HumanizeRec(rec)) } - return neu + ctx.Log(rec) }