]> Cypherpunks.ru repositories - nncp.git/blob - src/cypherpunks.ru/nncp/log.go
Initial
[nncp.git] / src / cypherpunks.ru / nncp / log.go
1 /*
2 NNCP -- Node-to-Node CoPy
3 Copyright (C) 2016-2017 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, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package nncp
20
21 import (
22         "fmt"
23         "os"
24         "sort"
25         "strings"
26         "time"
27
28         "golang.org/x/sys/unix"
29 )
30
31 type LogLevel string
32
33 type SDS map[string]interface{}
34
35 func sdFmt(who string, sds SDS) string {
36         keys := make([]string, 0, len(sds))
37         for k, _ := range sds {
38                 keys = append(keys, k)
39         }
40         sort.Strings(keys)
41         result := make([]string, 0, 1+len(keys))
42         result = append(result, "["+who)
43         for _, k := range keys {
44                 result = append(result, fmt.Sprintf(`%s="%s"`, k, sds[k]))
45         }
46         return strings.Join(result, " ") + "]"
47 }
48
49 func msgFmt(level LogLevel, who string, sds SDS, msg string) string {
50         result := fmt.Sprintf(
51                 "%s %s %s",
52                 level,
53                 time.Now().UTC().Format(time.RFC3339Nano),
54                 sdFmt(who, sds),
55         )
56         if len(msg) > 0 {
57                 result += " " + msg
58         }
59         return result + "\n"
60 }
61
62 func (ctx *Ctx) Log(msg string) {
63         fdLock, err := os.OpenFile(
64                 ctx.LogPath+".lock",
65                 os.O_CREATE|os.O_WRONLY,
66                 os.FileMode(0600),
67         )
68         if err != nil {
69                 fmt.Fprintln(os.Stderr, "Can not open lock for log:", err)
70                 return
71         }
72         fdLockFd := int(fdLock.Fd())
73         err = unix.Flock(fdLockFd, unix.LOCK_EX)
74         if err != nil {
75                 fmt.Fprintln(os.Stderr, "Can not acquire lock for log:", err)
76                 return
77         }
78         defer unix.Flock(fdLockFd, unix.LOCK_UN)
79         fd, err := os.OpenFile(
80                 ctx.LogPath,
81                 os.O_CREATE|os.O_WRONLY|os.O_APPEND,
82                 os.FileMode(0600),
83         )
84         if err != nil {
85                 fmt.Fprintln(os.Stderr, "Can not open log:", err)
86                 return
87         }
88         fd.WriteString(msg)
89         fd.Close()
90 }
91
92 func (ctx *Ctx) LogD(who string, sds SDS, msg string) {
93         if !ctx.Debug {
94                 return
95         }
96         fmt.Fprint(os.Stderr, msgFmt(LogLevel("D"), who, sds, msg))
97 }
98
99 func (ctx *Ctx) LogI(who string, sds SDS, msg string) {
100         msg = msgFmt(LogLevel("I"), who, sds, msg)
101         fmt.Fprintln(os.Stderr, ctx.Humanize(msg))
102         ctx.Log(msg)
103 }
104
105 func (ctx *Ctx) LogP(who string, sds SDS, msg string) {
106         fmt.Fprintln(os.Stderr, ctx.Humanize(msgFmt(LogLevel("P"), who, sds, msg)))
107 }
108
109 func (ctx *Ctx) LogE(who string, sds SDS, msg string) {
110         msg = msgFmt(LogLevel("E"), who, sds, msg)
111         fmt.Fprintln(os.Stderr, ctx.Humanize(msg))
112         ctx.Log(msg)
113 }
114
115 func SdsAdd(sds, add SDS) SDS {
116         neu := SDS{}
117         for k, v := range sds {
118                 neu[k] = v
119         }
120         for k, v := range add {
121                 neu[k] = v
122         }
123         return neu
124 }