]> Cypherpunks.ru repositories - nncp.git/blob - src/cypherpunks.ru/nncp/log.go
Forbid any later GNU GPL versions autousage
[nncp.git] / src / cypherpunks.ru / nncp / log.go
1 /*
2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2019 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         "fmt"
22         "os"
23         "sort"
24         "strings"
25         "time"
26
27         "golang.org/x/sys/unix"
28 )
29
30 type LogLevel string
31
32 type SDS map[string]interface{}
33
34 func sdFmt(who string, sds SDS) string {
35         keys := make([]string, 0, len(sds))
36         for k, _ := range sds {
37                 keys = append(keys, k)
38         }
39         sort.Strings(keys)
40         result := make([]string, 0, 1+len(keys))
41         result = append(result, "["+who)
42         for _, k := range keys {
43                 result = append(result, fmt.Sprintf(`%s="%s"`, k, sds[k]))
44         }
45         return strings.Join(result, " ") + "]"
46 }
47
48 func msgFmt(level LogLevel, who string, sds SDS, msg string) string {
49         result := fmt.Sprintf(
50                 "%s %s %s",
51                 level,
52                 time.Now().UTC().Format(time.RFC3339Nano),
53                 sdFmt(who, sds),
54         )
55         if len(msg) > 0 {
56                 result += " " + msg
57         }
58         return result + "\n"
59 }
60
61 func (ctx *Ctx) Log(msg string) {
62         fdLock, err := os.OpenFile(
63                 ctx.LogPath+".lock",
64                 os.O_CREATE|os.O_WRONLY,
65                 os.FileMode(0600),
66         )
67         if err != nil {
68                 fmt.Fprintln(os.Stderr, "Can not open lock for log:", err)
69                 return
70         }
71         fdLockFd := int(fdLock.Fd())
72         err = unix.Flock(fdLockFd, unix.LOCK_EX)
73         if err != nil {
74                 fmt.Fprintln(os.Stderr, "Can not acquire lock for log:", err)
75                 return
76         }
77         defer unix.Flock(fdLockFd, unix.LOCK_UN)
78         fd, err := os.OpenFile(
79                 ctx.LogPath,
80                 os.O_CREATE|os.O_WRONLY|os.O_APPEND,
81                 os.FileMode(0600),
82         )
83         if err != nil {
84                 fmt.Fprintln(os.Stderr, "Can not open log:", err)
85                 return
86         }
87         fd.WriteString(msg)
88         fd.Close()
89 }
90
91 func (ctx *Ctx) LogD(who string, sds SDS, msg string) {
92         if !ctx.Debug {
93                 return
94         }
95         fmt.Fprint(os.Stderr, msgFmt(LogLevel("D"), who, sds, msg))
96 }
97
98 func (ctx *Ctx) LogI(who string, sds SDS, msg string) {
99         msg = msgFmt(LogLevel("I"), who, sds, msg)
100         if !ctx.Quiet {
101                 fmt.Fprintln(os.Stderr, ctx.Humanize(msg))
102         }
103         ctx.Log(msg)
104 }
105
106 func (ctx *Ctx) LogP(who string, sds SDS, msg string) {
107         if !ctx.Quiet {
108                 fmt.Fprintln(os.Stderr, ctx.Humanize(msgFmt(LogLevel("P"), who, sds, msg)))
109         }
110 }
111
112 func (ctx *Ctx) LogE(who string, sds SDS, msg string) {
113         msg = msgFmt(LogLevel("E"), who, sds, msg)
114         if len(msg) > 2048 {
115                 msg = msg[:2048]
116         }
117         fmt.Fprintln(os.Stderr, ctx.Humanize(msg))
118         ctx.Log(msg)
119 }
120
121 func SdsAdd(sds, add SDS) SDS {
122         neu := SDS{}
123         for k, v := range sds {
124                 neu[k] = v
125         }
126         for k, v := range add {
127                 neu[k] = v
128         }
129         return neu
130 }