]> Cypherpunks.ru repositories - goredo.git/blob - log.go
f4248de80d30a9d73146d688489f0d18efb2b886
[goredo.git] / log.go
1 /*
2 goredo -- djb's redo implementation on pure Go
3 Copyright (C) 2020-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 // Logging facilities
19
20 package main
21
22 import (
23         "bytes"
24         "flag"
25         "fmt"
26         "os"
27         "strings"
28         "sync"
29
30         "golang.org/x/term"
31 )
32
33 const (
34         EnvLevel      = "REDO_LEVEL"
35         EnvNoProgress = "REDO_NO_PROGRESS"
36         EnvDebug      = "REDO_DEBUG"
37         EnvLogWait    = "REDO_LOG_WAIT"
38         EnvLogLock    = "REDO_LOG_LOCK"
39         EnvLogPid     = "REDO_LOG_PID"
40         EnvLogJS      = "REDO_LOG_JS"
41         EnvNoColor    = "NO_COLOR"
42 )
43
44 var (
45         Level      = 0
46         NoColor    bool
47         NoProgress bool
48         Debug      bool
49         LogWait    bool
50         LogLock    bool
51         LogJS      bool
52         MyPid      int
53
54         CDebug string
55         CRedo  string
56         CWait  string
57         CLock  string
58         CErr   string
59         CWarn  string
60         CJS    string
61         CReset string
62         CNone  string = "NONE"
63
64         flagNoProgress = flag.Bool("no-progress", false, fmt.Sprintf("no progress printing (%s=1), also implies -no-status", EnvNoProgress))
65         flagDebug      = flag.Bool("d", false, fmt.Sprintf("enable debug logging (%s=1)", EnvDebug))
66         flagLogWait    = flag.Bool("log-wait", false, fmt.Sprintf("enable wait messages logging (%s=1)", EnvLogWait))
67         flagLogLock    = flag.Bool("log-lock", false, fmt.Sprintf("enable lock messages logging (%s=1)", EnvLogLock))
68         flagLogPid     = flag.Bool("log-pid", false, fmt.Sprintf("append PIDs (%s=1)", EnvLogPid))
69         flagLogJS      = flag.Bool("log-js", false, fmt.Sprintf("enable jobserver messages logging (%s=1)", EnvLogJS))
70
71         LogMutex     sync.Mutex
72         KeyEraseLine string
73         LogWasStatus bool
74 )
75
76 func init() {
77         var b bytes.Buffer
78         t := term.NewTerminal(&b, "")
79         CDebug = string(t.Escape.Yellow)
80         CRedo = string(t.Escape.Green)
81         CWait = string(t.Escape.Blue)
82         CLock = string(t.Escape.Cyan)
83         CErr = string(t.Escape.Red)
84         CWarn = string(t.Escape.Magenta)
85         CJS = string(t.Escape.White)
86         CReset = string(t.Escape.Reset)
87         KeyEraseLine = fmt.Sprintf("%s[K", CReset[0:1])
88 }
89
90 func erasedStatus(s, end string) string {
91         if LogWasStatus {
92                 s += KeyEraseLine
93         }
94         return s + end
95 }
96
97 func trace(level, format string, args ...interface{}) {
98         var p string
99         if MyPid != 0 {
100                 p = fmt.Sprintf("[%d] ", MyPid)
101         }
102         switch level {
103         case CNone:
104                 p = StderrPrefix + p + fmt.Sprintf(format, args...)
105                 LogMutex.Lock()
106                 os.Stderr.WriteString(erasedStatus(p, "\n"))
107                 LogWasStatus = false
108                 LogMutex.Unlock()
109                 return
110         case CDebug:
111                 if !Debug {
112                         return
113                 }
114                 p += "dbg  "
115         case CWait:
116                 if !(LogWait || Debug) {
117                         return
118                 }
119                 p += "wait "
120         case CRedo:
121                 if NoProgress {
122                         return
123                 }
124                 p += "redo "
125         case CLock:
126                 if !(LogLock || Debug) {
127                         return
128                 }
129                 p += "lock "
130         case CJS:
131                 if !(LogJS || Debug) {
132                         return
133                 }
134                 p += "js   "
135         case CErr:
136                 p += "err  "
137         case CWarn:
138                 p += "warn "
139         }
140         msg := fmt.Sprintf(format, args...)
141         msg = StderrPrefix + colourize(level, p+strings.Repeat(". ", Level)+msg)
142         LogMutex.Lock()
143         os.Stderr.WriteString(erasedStatus(msg, "\n"))
144         LogWasStatus = false
145         LogMutex.Unlock()
146 }
147
148 func colourize(colour, s string) string {
149         if NoColor {
150                 return s
151         }
152         return colour + s + CReset
153 }