]> Cypherpunks.ru repositories - nncp.git/blob - src/log.go
7bb59a3b97cf798e5c35c01d0c76c19154445ba6
[nncp.git] / src / log.go
1 /*
2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2021 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         "time"
25
26         "go.cypherpunks.ru/recfile"
27         "golang.org/x/sys/unix"
28 )
29
30 type LE struct {
31         K string
32         V interface{}
33 }
34 type LEs []LE
35
36 func (les LEs) Rec() string {
37         fields := make([]recfile.Field, 0, len(les)+1)
38         fields = append(fields, recfile.Field{
39                 Name: "When", Value: time.Now().UTC().Format(time.RFC3339Nano),
40         })
41         var val string
42         for _, le := range les {
43                 switch v := le.V.(type) {
44                 case int, int8, uint8, int64, uint64:
45                         val = fmt.Sprintf("%d", v)
46                 case bool:
47                         val = fmt.Sprintf("%v", v)
48                 default:
49                         val = fmt.Sprintf("%s", v)
50                 }
51                 fields = append(fields, recfile.Field{Name: le.K, Value: val})
52         }
53         b := bytes.NewBuffer(make([]byte, 0, 1<<10))
54         w := recfile.NewWriter(b)
55         _, err := w.RecordStart()
56         if err != nil {
57                 panic(err)
58         }
59         _, err = w.WriteFields(fields...)
60         if err != nil {
61                 panic(err)
62         }
63         return b.String()
64 }
65
66 func (ctx *Ctx) Log(rec string) {
67         fdLock, err := os.OpenFile(
68                 ctx.LogPath+".lock",
69                 os.O_CREATE|os.O_WRONLY,
70                 os.FileMode(0666),
71         )
72         if err != nil {
73                 fmt.Fprintln(os.Stderr, "Can not open lock for log:", err)
74                 return
75         }
76         defer fdLock.Close()
77         fdLockFd := int(fdLock.Fd())
78         err = unix.Flock(fdLockFd, unix.LOCK_EX)
79         if err != nil {
80                 fmt.Fprintln(os.Stderr, "Can not acquire lock for log:", err)
81                 return
82         }
83         defer unix.Flock(fdLockFd, unix.LOCK_UN)
84         fd, err := os.OpenFile(
85                 ctx.LogPath,
86                 os.O_CREATE|os.O_WRONLY|os.O_APPEND,
87                 os.FileMode(0666),
88         )
89         if err != nil {
90                 fmt.Fprintln(os.Stderr, "Can not open log:", err)
91                 return
92         }
93         fd.WriteString(rec) // #nosec G104
94         fd.Close()          // #nosec G104
95 }
96
97 func (ctx *Ctx) LogD(who string, les LEs, msg func(LEs) string) {
98         if !ctx.Debug {
99                 return
100         }
101         les = append(LEs{{"Debug", true}, {"Who", who}}, les...)
102         les = append(les, LE{"Msg", msg(les)})
103         fmt.Fprint(os.Stderr, les.Rec())
104 }
105
106 func (ctx *Ctx) LogI(who string, les LEs, msg func(LEs) string) {
107         les = append(LEs{{"Who", who}}, les...)
108         les = append(les, LE{"Msg", msg(les)})
109         rec := les.Rec()
110         if !ctx.Quiet {
111                 fmt.Fprintln(os.Stderr, ctx.HumanizeRec(rec))
112         }
113         ctx.Log(rec)
114 }
115
116 func (ctx *Ctx) LogE(who string, les LEs, err error, msg func(LEs) string) {
117         les = append(LEs{{"Err", err.Error()}, {"Who", who}}, les...)
118         les = append(les, LE{"Msg", msg(les)})
119         rec := les.Rec()
120         if !ctx.Quiet {
121                 fmt.Fprintln(os.Stderr, ctx.HumanizeRec(rec))
122         }
123         ctx.Log(rec)
124 }