Repository navigation
Expand file tree
/
Copy pathoutput.go
More file actions
113 lines (92 loc) · 3.06 KB
/
Copy pathoutput.go
File metadata and controls
113 lines (92 loc) · 3.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package logging
import (
"fmt"
"net"
"strings"
)
const (
// StdOut is a predefined Target to log into the process standard output.
StdOut Target = "stdout"
// StdErr is a predefined Target to log into the process standard error.
StdErr Target = "stderr"
// SysLog is a predefined Target to route logging messages into the local syslog daemon over UDP localhost:514.
// Use a syslog URL to choose another transport or address, see Target.
SysLog Target = "syslog"
// DefaultOutput defines default output if omitted.
DefaultOutput = StdOut
defaultSyslogNetwork = "udp"
defaultSyslogAddress = "localhost:514"
)
// Target identifies logging output target. It is one of:
//
// - StdOut, StdErr: process standard streams;
// - SysLog: syslog over UDP to localhost:514;
// - syslog URL: "syslog://host:port" (UDP), "syslog+udp://host:port", "syslog+tcp://host:port",
// "syslog+unixgram:///dev/log" or "syslog+unix:///dev/log";
// - a name registered with RegisterOutput;
// - anything else is a path of a log file. The file is created if missing and appended otherwise.
type Target string
// String returns string representation of Target.
func (output Target) String() string {
return string(output)
}
// Validate returns error if Target settings is not valid.
func (output Target) Validate() error {
switch output {
case "":
return fmt.Errorf("%w: output empty, want '%v', '%v', '%v', syslog URL or file path",
Error, StdOut, StdErr, SysLog)
case StdOut, StdErr, SysLog:
return nil
}
if _, _, isSyslog, err := parseSyslogTarget(output); isSyslog {
return err
}
if strings.ContainsRune(string(output), 0) {
return fmt.Errorf("%w: output %q contains NUL character", Error, string(output))
}
return nil
}
// isSyslog reports the target routes messages to syslog.
func (output Target) isSyslog() bool {
_, _, isSyslog, _ := parseSyslogTarget(output)
return isSyslog
}
// parseSyslogTarget detects the target is a syslog one and extracts network and address to connect.
// Returns isSyslog false for any other target. Returns isSyslog true and error for malformed syslog URLs.
func parseSyslogTarget(target Target) (network, address string, isSyslog bool, err error) {
if target == SysLog {
return defaultSyslogNetwork, defaultSyslogAddress, true, nil
}
scheme, rest, found := strings.Cut(string(target), "://")
if !found {
return "", "", false, nil
}
switch scheme {
case "syslog", "syslog+udp":
network = "udp"
case "syslog+tcp":
network = "tcp"
case "syslog+unixgram":
network = "unixgram"
case "syslog+unix":
network = "unix"
default:
return "", "", false, nil
}
if rest == "" {
return "", "", true, fmt.Errorf("%w: syslog address empty in %q", Error, string(target))
}
if network == "udp" || network == "tcp" {
if _, _, err = net.SplitHostPort(rest); err != nil {
return "", "", true, wrapErr(err, "syslog address %q", rest)
}
}
return network, rest, true, nil
}
// WithTarget is an Option setting the output Target in Config.
func WithTarget(target Target) Option {
return func(config *Config) {
config.Output = target
}
}