]> Cypherpunks.ru repositories - nncp.git/blob - src/log.go
Raise copyright years
[nncp.git] / src / log.go
1 /*
2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2022 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package nncp
19
20 import (
21         "bytes"
22         "fmt"
23         "os"
24         "sync"
25         "time"
26
27         "go.cypherpunks.ru/recfile"
28         "golang.org/x/sys/unix"
29 )
30
31 const LogFdPrefix = "FD:"
32
33 var (
34         LogFd     *os.File
35         LogFdLock sync.Mutex
36 )
37
38 type LE struct {
39         K string
40         V interface{}
41 }
42 type LEs []LE
43
44 func (les LEs) Rec() string {
45         b := bytes.NewBuffer(make([]byte, 0, 1<<10))
46         w := recfile.NewWriter(b)
47         _, err := w.RecordStart()
48         if err != nil {
49                 panic(err)
50         }
51         _, err = w.WriteFields(recfile.Field{
52                 Name:  "When",
53                 Value: time.Now().UTC().Format(time.RFC3339Nano),
54         })
55         if err != nil {
56                 panic(err)
57         }
58         for _, le := range les {
59                 switch v := le.V.(type) {
60                 case int, int8, uint8, int64, uint64:
61                         _, err = w.WriteFields(recfile.Field{
62                                 Name:  le.K,
63                                 Value: fmt.Sprintf("%d", v),
64                         })
65                 case bool:
66                         _, err = w.WriteFields(recfile.Field{
67                                 Name:  le.K,
68                                 Value: fmt.Sprintf("%v", v),
69                         })
70                 case []string:
71                         if len(v) > 0 {
72                                 _, err = w.WriteFieldMultiline(le.K, v)
73                         }
74                 default:
75                         _, err = w.WriteFields(recfile.Field{
76                                 Name:  le.K,
77                                 Value: fmt.Sprintf("%s", v),
78                         })
79                 }
80                 if err != nil {
81                         panic(err)
82                 }
83         }
84         return b.String()
85 }
86
87 func (ctx *Ctx) Log(rec string) {
88         if LogFd != nil {
89                 LogFdLock.Lock()
90                 LogFd.WriteString(rec)
91                 LogFdLock.Unlock()
92                 return
93         }
94         fdLock, err := os.OpenFile(
95                 ctx.LogPath+".lock",
96                 os.O_CREATE|os.O_WRONLY,
97                 os.FileMode(0666),
98         )
99         if err != nil {
100                 fmt.Fprintln(os.Stderr, "Can not open lock for log:", err)
101                 return
102         }
103         defer fdLock.Close()
104         fdLockFd := int(fdLock.Fd())
105         err = unix.Flock(fdLockFd, unix.LOCK_EX)
106         if err != nil {
107                 fmt.Fprintln(os.Stderr, "Can not acquire lock for log:", err)
108                 return
109         }
110         defer unix.Flock(fdLockFd, unix.LOCK_UN)
111         fd, err := os.OpenFile(
112                 ctx.LogPath,
113                 os.O_CREATE|os.O_WRONLY|os.O_APPEND,
114                 os.FileMode(0666),
115         )
116         if err != nil {
117                 fmt.Fprintln(os.Stderr, "Can not open log:", err)
118                 return
119         }
120         fd.WriteString(rec)
121         fd.Close()
122 }
123
124 func (ctx *Ctx) LogD(who string, les LEs, msg func(LEs) string) {
125         if !ctx.Debug {
126                 return
127         }
128         les = append(LEs{{"Debug", true}, {"Who", who}}, les...)
129         les = append(les, LE{"Msg", msg(les)})
130         fmt.Fprint(os.Stderr, les.Rec())
131 }
132
133 func (ctx *Ctx) LogI(who string, les LEs, msg func(LEs) string) {
134         les = append(LEs{{"Who", who}}, les...)
135         les = append(les, LE{"Msg", msg(les)})
136         rec := les.Rec()
137         if ctx.Debug {
138                 fmt.Fprint(os.Stderr, rec)
139         }
140         if !ctx.Quiet {
141                 fmt.Fprintln(os.Stderr, ctx.HumanizeRec(rec))
142         }
143         ctx.Log(rec)
144 }
145
146 func (ctx *Ctx) LogE(who string, les LEs, err error, msg func(LEs) string) {
147         les = append(LEs{{"Err", err.Error()}, {"Who", who}}, les...)
148         les = append(les, LE{"Msg", msg(les)})
149         rec := les.Rec()
150         if ctx.Debug {
151                 fmt.Fprint(os.Stderr, rec)
152         }
153         if !ctx.Quiet {
154                 fmt.Fprintln(os.Stderr, ctx.HumanizeRec(rec))
155         }
156         ctx.Log(rec)
157 }