]> ruderich.org/simon Gitweb - safcm/safcm.git/blob - frontend/log.go
3bb511860ccb46cbd4f2c44286caba9a1e02c915
[safcm/safcm.git] / frontend / log.go
1 // Frontend: Logging functions for programs using the safcm library
2
3 // Copyright (C) 2021-2022  Simon Ruderich
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 package frontend
19
20 import (
21         "fmt"
22         "log"
23
24         "ruderich.org/simon/safcm"
25         "ruderich.org/simon/safcm/rpc"
26 )
27
28 type Event struct {
29         Host Host
30
31         // Only one of Error, Log and ConnEvent is set in a single event
32         Error     error
33         Log       Log
34         ConnEvent rpc.ConnEvent
35
36         Escaped bool // true if untrusted input is already escaped
37 }
38
39 type Log struct {
40         Level safcm.LogLevel
41         Text  string
42 }
43
44 func (l *Loop) Log(host Host, level safcm.LogLevel, escaped bool,
45         msg string) {
46
47         l.events <- Event{
48                 Host: host,
49                 Log: Log{
50                         Level: level,
51                         Text:  msg,
52                 },
53                 Escaped: escaped,
54         }
55 }
56
57 // LogEvent logs events using the log package. It can be used to implement
58 // Loop.LogEventFunc. It's used by cmd/safcm to log events.
59 func LogEvent(x Event, level safcm.LogLevel, isTTY bool,
60         failed *bool) {
61
62         // We have multiple event sources so this is somewhat ugly.
63         var prefix, data string
64         var color Color
65         if x.Error != nil {
66                 prefix = "[error]"
67                 data = x.Error.Error()
68                 color = ColorRed
69                 // We logged an error, tell the caller
70                 *failed = true
71         } else if x.Log.Level != 0 {
72                 if level < x.Log.Level {
73                         return
74                 }
75                 // LogError and LogDebug3 should not occur here
76                 switch x.Log.Level {
77                 case safcm.LogInfo:
78                         prefix = "[info]"
79                 case safcm.LogVerbose:
80                         prefix = "[verbose]"
81                 case safcm.LogDebug:
82                         prefix = "[debug]"
83                 case safcm.LogDebug2:
84                         prefix = "[debug2]"
85                 default:
86                         prefix = fmt.Sprintf("[INVALID=%d]", x.Log.Level)
87                         color = ColorRed
88                 }
89                 data = x.Log.Text
90         } else {
91                 switch x.ConnEvent.Type {
92                 case rpc.ConnEventStderr:
93                         prefix = "[stderr]"
94                 case rpc.ConnEventDebug:
95                         prefix = "[debug3]"
96                 case rpc.ConnEventUpload:
97                         if level < safcm.LogInfo {
98                                 return
99                         }
100                         prefix = "[info]"
101                         x.ConnEvent.Data = "remote helper upload in progress"
102                 default:
103                         prefix = fmt.Sprintf("[INVALID=%d]", x.ConnEvent.Type)
104                         color = ColorRed
105                 }
106                 data = x.ConnEvent.Data
107         }
108
109         host := x.Host.Name()
110         if color != 0 {
111                 host = ColorString(isTTY, color, host)
112         }
113         // Make sure to escape control characters to prevent terminal
114         // injection attacks
115         if !x.Escaped {
116                 data = EscapeControlCharacters(isTTY, data)
117         }
118         log.Printf("%-9s [%s] %s", prefix, host, data)
119 }