New upstream version 0.0~git20180709.a4725f0
Arnaud Rebillout
3 years ago
0 | .cover |
89 | 89 | w.Write([]byte("these are some bytes")) |
90 | 90 | ``` |
91 | 91 | |
92 | If you need further control over connection attempts, you can use the DialWithCustomDialer | |
93 | function. To continue with the DialWithTLSConfig example: | |
94 | ||
95 | ``` | |
96 | netDialer := &net.Dialer{Timeout: time.Second*5} // easy timeouts | |
97 | realNetwork := "tcp" // real network, other vars your dail func can close over | |
98 | dial := func(network, addr string) (net.Conn, error) { | |
99 | // cannot use "network" here as it'll simply be "custom" which will fail | |
100 | return tls.DialWithDialer(netDialer, realNetwork, addr, &config) | |
101 | } | |
102 | ||
103 | w, err := DialWithCustomDialer("custom", "192.168.0.52:514", syslog.LOG_ERR, "testtag", dial) | |
104 | ``` | |
105 | ||
106 | Your custom dial func can set timeouts, proxy connections, and do whatever else it needs before returning a net.Conn. | |
107 | ||
92 | 108 | # Generating TLS Certificates |
93 | 109 | |
94 | 110 | We've provided a script that you can use to generate a self-signed keypair: |
36 | 36 | dialers := map[string]dialerFunctionWrapper{ |
37 | 37 | "": dialerFunctionWrapper{"unixDialer", w.unixDialer}, |
38 | 38 | "tcp+tls": dialerFunctionWrapper{"tlsDialer", w.tlsDialer}, |
39 | "custom": dialerFunctionWrapper{"customDialer", w.customDialer}, | |
39 | 40 | } |
40 | 41 | dialer, ok := dialers[w.network] |
41 | 42 | if !ok { |
84 | 85 | } |
85 | 86 | return sc, hostname, err |
86 | 87 | } |
88 | ||
89 | // customDialer uses the custom dialer when the Writer was created | |
90 | // giving developers total control over how connections are made and returned. | |
91 | // Note it does not check if cdialer is nil, as it should only be referenced from getDialer. | |
92 | func (w *Writer) customDialer() (serverConn, string, error) { | |
93 | c, err := w.customDial(w.network, w.raddr) | |
94 | var sc serverConn | |
95 | hostname := w.hostname | |
96 | if err == nil { | |
97 | sc = &netConn{conn: c} | |
98 | if hostname == "" { | |
99 | hostname = c.LocalAddr().String() | |
100 | } | |
101 | } | |
102 | return sc, hostname, err | |
103 | } |
2 | 2 | import ( |
3 | 3 | "crypto/tls" |
4 | 4 | "crypto/x509" |
5 | "errors" | |
5 | 6 | "io/ioutil" |
7 | "net" | |
6 | 8 | "testing" |
7 | 9 | ) |
8 | 10 | |
42 | 44 | dialer = w.getDialer() |
43 | 45 | if "basicDialer" != dialer.Name { |
44 | 46 | t.Errorf("should get basicDialer, got: %v", dialer) |
47 | } | |
48 | ||
49 | w.network = "custom" | |
50 | w.customDial = func(string, string) (net.Conn, error) { return nil, nil } | |
51 | dialer = w.getDialer() | |
52 | if "customDialer" != dialer.Name { | |
53 | t.Errorf("should get customDialer, got: %v", dialer) | |
45 | 54 | } |
46 | 55 | } |
47 | 56 | |
195 | 204 | t.Errorf("should not interfere with hostname") |
196 | 205 | } |
197 | 206 | } |
207 | ||
208 | func TestCustomDialer(t *testing.T) { | |
209 | // A custom dialer can really be anything, so we don't test an actual connection | |
210 | // instead we test the behavior of this code path | |
211 | ||
212 | nwork, addr := "custom", "custom_addr_to_pass" | |
213 | w := Writer{ | |
214 | priority: LOG_ERR, | |
215 | tag: "tag", | |
216 | hostname: "", | |
217 | network: nwork, | |
218 | raddr: addr, | |
219 | customDial: func(n string, a string) (net.Conn, error) { | |
220 | if n != nwork || a != addr { | |
221 | return nil, errors.New("Unexpected network or address, expected: (" + | |
222 | nwork + ":" + addr + ") but received (" + n + ":" + a + ")") | |
223 | } | |
224 | return fakeConn{addr: &fakeAddr{nwork, addr}}, nil | |
225 | }, | |
226 | } | |
227 | ||
228 | _, hostname, err := w.customDialer() | |
229 | ||
230 | if err != nil { | |
231 | t.Errorf("failed to dial: %v", err) | |
232 | } | |
233 | ||
234 | if hostname == "" { | |
235 | t.Errorf("should set default hostname") | |
236 | } | |
237 | ||
238 | w.hostname = "my other hostname" | |
239 | ||
240 | _, hostname, err = w.customDialer() | |
241 | ||
242 | if err != nil { | |
243 | t.Errorf("failed to dial: %v", err) | |
244 | } | |
245 | ||
246 | if hostname != "my other hostname" { | |
247 | t.Errorf("should not interfere with hostname") | |
248 | } | |
249 | } | |
250 | ||
251 | type fakeConn struct { | |
252 | net.Conn | |
253 | addr net.Addr | |
254 | } | |
255 | ||
256 | func (fc fakeConn) Close() error { | |
257 | return nil | |
258 | } | |
259 | ||
260 | func (fc fakeConn) Write(p []byte) (int, error) { | |
261 | return len(p), nil | |
262 | } | |
263 | ||
264 | func (fc fakeConn) LocalAddr() net.Addr { | |
265 | return fc.addr | |
266 | } | |
267 | ||
268 | type fakeAddr struct { | |
269 | nwork, addr string | |
270 | } | |
271 | ||
272 | func (fa *fakeAddr) Network() string { | |
273 | return fa.nwork | |
274 | } | |
275 | ||
276 | func (fa *fakeAddr) String() string { | |
277 | return fa.addr | |
278 | } |
4 | 4 | "os" |
5 | 5 | "time" |
6 | 6 | ) |
7 | ||
8 | const appNameMaxLength = 48 // limit to 48 chars as per RFC5424 | |
7 | 9 | |
8 | 10 | // Formatter is a type of function that takes the consituent parts of a |
9 | 11 | // syslog message and returns a formatted string. A different Formatter is |
31 | 33 | // RFC3164Formatter provides an RFC 3164 compliant message. |
32 | 34 | func RFC3164Formatter(p Priority, hostname, tag, content string) string { |
33 | 35 | timestamp := time.Now().Format(time.Stamp) |
34 | msg := fmt.Sprintf("<%d> %s %s %s[%d]: %s", | |
36 | msg := fmt.Sprintf("<%d>%s %s %s[%d]: %s", | |
35 | 37 | p, timestamp, hostname, tag, os.Getpid(), content) |
36 | 38 | return msg |
39 | } | |
40 | ||
41 | // if string's length is greater than max, then use the last part | |
42 | func truncateStartStr(s string, max int) string { | |
43 | if (len(s) > max) { | |
44 | return s[len(s) - max:] | |
45 | } | |
46 | return s | |
37 | 47 | } |
38 | 48 | |
39 | 49 | // RFC5424Formatter provides an RFC 5424 compliant message. |
40 | 50 | func RFC5424Formatter(p Priority, hostname, tag, content string) string { |
41 | 51 | timestamp := time.Now().Format(time.RFC3339) |
42 | 52 | pid := os.Getpid() |
43 | appName := os.Args[0] | |
44 | msg := fmt.Sprintf("<%d>%d %s %s %s %d %s %s", | |
53 | appName := truncateStartStr(os.Args[0], appNameMaxLength) | |
54 | msg := fmt.Sprintf("<%d>%d %s %s %s %d %s - %s", | |
45 | 55 | p, 1, timestamp, hostname, appName, pid, tag, content) |
46 | 56 | return msg |
47 | 57 | } |
4 | 4 | "os" |
5 | 5 | "testing" |
6 | 6 | "time" |
7 | "strings" | |
7 | 8 | ) |
8 | 9 | |
9 | 10 | func TestDefaultFormatter(t *testing.T) { |
26 | 27 | |
27 | 28 | func TestRFC3164Formatter(t *testing.T) { |
28 | 29 | out := RFC3164Formatter(LOG_ERR, "hostname", "tag", "content") |
29 | expected := fmt.Sprintf("<%d> %s %s %s[%d]: %s", | |
30 | expected := fmt.Sprintf("<%d>%s %s %s[%d]: %s", | |
30 | 31 | LOG_ERR, time.Now().Format(time.Stamp), "hostname", "tag", os.Getpid(), "content") |
31 | 32 | if out != expected { |
32 | 33 | t.Errorf("expected %v got %v", expected, out) |
35 | 36 | |
36 | 37 | func TestRFC5424Formatter(t *testing.T) { |
37 | 38 | out := RFC5424Formatter(LOG_ERR, "hostname", "tag", "content") |
38 | expected := fmt.Sprintf("<%d>%d %s %s %s %d %s %s", | |
39 | LOG_ERR, 1, time.Now().Format(time.RFC3339), "hostname", os.Args[0], os.Getpid(), "tag", "content") | |
39 | expected := fmt.Sprintf("<%d>%d %s %s %s %d %s - %s", | |
40 | LOG_ERR, 1, time.Now().Format(time.RFC3339), "hostname", truncateStartStr(os.Args[0], appNameMaxLength), | |
41 | os.Getpid(), "tag", "content") | |
40 | 42 | if out != expected { |
41 | 43 | t.Errorf("expected %v got %v", expected, out) |
42 | 44 | } |
43 | 45 | } |
46 | ||
47 | func TestTruncateStartStr(t *testing.T) { | |
48 | out := truncateStartStr("abcde", 3) | |
49 | if strings.Compare(out, "cde" ) != 0 { | |
50 | t.Errorf("expected \"cde\" got %v", out) | |
51 | } | |
52 | out = truncateStartStr("abcde", 5) | |
53 | if strings.Compare(out, "abcde" ) != 0 { | |
54 | t.Errorf("expected \"abcde\" got %v", out) | |
55 | } | |
56 | }⏎ |
2 | 2 | import ( |
3 | 3 | "crypto/tls" |
4 | 4 | "crypto/x509" |
5 | "errors" | |
5 | 6 | "io/ioutil" |
6 | 7 | "log" |
8 | "net" | |
7 | 9 | "os" |
8 | 10 | ) |
9 | 11 | |
13 | 15 | writeString(framer Framer, formatter Formatter, p Priority, hostname, tag, s string) error |
14 | 16 | close() error |
15 | 17 | } |
18 | ||
19 | // DialFunc is the function signature to be used for a custom dialer callback | |
20 | // with DialWithCustomDialer | |
21 | type DialFunc func(string, string) (net.Conn, error) | |
16 | 22 | |
17 | 23 | // New establishes a new connection to the system log daemon. Each |
18 | 24 | // write to the returned Writer sends a log message with the given |
28 | 34 | // If network is empty, Dial will connect to the local syslog server. |
29 | 35 | func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) { |
30 | 36 | return DialWithTLSConfig(network, raddr, priority, tag, nil) |
37 | } | |
38 | ||
39 | // ErrNilDialFunc is returned from DialWithCustomDialer when a nil DialFunc is passed, | |
40 | // avoiding a nil pointer deference panic. | |
41 | var ErrNilDialFunc = errors.New("srslog: nil DialFunc passed to DialWithCustomDialer") | |
42 | ||
43 | // DialWithCustomDialer establishes a connection by calling customDial. | |
44 | // Each write to the returned Writer sends a log message with the given facility, severity and tag. | |
45 | // Network must be "custom" in order for this package to use customDial. | |
46 | // While network and raddr will be passed to customDial, it is allowed for customDial to ignore them. | |
47 | // If customDial is nil, this function returns ErrNilDialFunc. | |
48 | func DialWithCustomDialer(network, raddr string, priority Priority, tag string, customDial DialFunc) (*Writer, error) { | |
49 | if customDial == nil { | |
50 | return nil, ErrNilDialFunc | |
51 | } | |
52 | return dialAllParameters(network, raddr, priority, tag, nil, customDial) | |
31 | 53 | } |
32 | 54 | |
33 | 55 | // DialWithTLSCertPath establishes a secure connection to a log daemon by connecting to |
58 | 80 | // DialWithTLSConfig establishes a secure connection to a log daemon by connecting to |
59 | 81 | // address raddr on the specified network. It uses tlsConfig to configure the secure connection. |
60 | 82 | func DialWithTLSConfig(network, raddr string, priority Priority, tag string, tlsConfig *tls.Config) (*Writer, error) { |
83 | return dialAllParameters(network, raddr, priority, tag, tlsConfig, nil) | |
84 | } | |
85 | ||
86 | // implementation of the various functions above | |
87 | func dialAllParameters(network, raddr string, priority Priority, tag string, tlsConfig *tls.Config, customDial DialFunc) (*Writer, error) { | |
61 | 88 | if err := validatePriority(priority); err != nil { |
62 | 89 | return nil, err |
63 | 90 | } |
68 | 95 | hostname, _ := os.Hostname() |
69 | 96 | |
70 | 97 | w := &Writer{ |
71 | priority: priority, | |
72 | tag: tag, | |
73 | hostname: hostname, | |
74 | network: network, | |
75 | raddr: raddr, | |
76 | tlsConfig: tlsConfig, | |
98 | priority: priority, | |
99 | tag: tag, | |
100 | hostname: hostname, | |
101 | network: network, | |
102 | raddr: raddr, | |
103 | tlsConfig: tlsConfig, | |
104 | customDial: customDial, | |
77 | 105 | } |
78 | 106 | |
79 | w.Lock() | |
80 | defer w.Unlock() | |
81 | ||
82 | err := w.connect() | |
107 | _, err := w.connect() | |
83 | 108 | if err != nil { |
84 | 109 | return nil, err |
85 | 110 | } |
39 | 39 | done <- rcvd |
40 | 40 | } |
41 | 41 | |
42 | var crashy = false | |
42 | type Crashy struct { | |
43 | sync.RWMutex | |
44 | is bool | |
45 | } | |
46 | ||
47 | func (c *Crashy) IsCrashy() bool { | |
48 | c.RLock() | |
49 | defer c.RUnlock() | |
50 | return c.is | |
51 | } | |
52 | ||
53 | func (c *Crashy) Set(is bool) { | |
54 | c.Lock() | |
55 | c.is = is | |
56 | c.Unlock() | |
57 | } | |
58 | ||
59 | var crashy = Crashy{is: false} | |
43 | 60 | |
44 | 61 | func testableNetwork(network string) bool { |
45 | 62 | switch network { |
69 | 86 | defer wg.Done() |
70 | 87 | c.SetReadDeadline(time.Now().Add(5 * time.Second)) |
71 | 88 | b := bufio.NewReader(c) |
72 | for ct := 1; !crashy || ct&7 != 0; ct++ { | |
89 | for ct := 1; !crashy.IsCrashy() || ct&7 != 0; ct++ { | |
73 | 90 | s, err := b.ReadString('\n') |
74 | 91 | if err != nil { |
75 | 92 | break |
452 | 469 | } |
453 | 470 | |
454 | 471 | func TestConcurrentReconnect(t *testing.T) { |
455 | crashy = true | |
456 | defer func() { crashy = false }() | |
472 | crashy.Set(true) | |
473 | defer func() { crashy.Set(false) }() | |
457 | 474 | |
458 | 475 | const N = 10 |
459 | 476 | const M = 100 |
7 | 7 | |
8 | 8 | // A Writer is a connection to a syslog server. |
9 | 9 | type Writer struct { |
10 | sync.Mutex // guards conn | |
11 | ||
12 | 10 | priority Priority |
13 | 11 | tag string |
14 | 12 | hostname string |
18 | 16 | framer Framer |
19 | 17 | formatter Formatter |
20 | 18 | |
19 | //non-nil if custom dialer set, used in getDialer | |
20 | customDial DialFunc | |
21 | ||
22 | mu sync.RWMutex // guards conn | |
21 | 23 | conn serverConn |
22 | 24 | } |
23 | 25 | |
26 | // getConn provides access to the internal conn, protected by a mutex. The | |
27 | // conn is threadsafe, so it can be used while unlocked, but we want to avoid | |
28 | // race conditions on grabbing a reference to it. | |
29 | func (w *Writer) getConn() serverConn { | |
30 | w.mu.RLock() | |
31 | conn := w.conn | |
32 | w.mu.RUnlock() | |
33 | return conn | |
34 | } | |
35 | ||
36 | // setConn updates the internal conn, protected by a mutex. | |
37 | func (w *Writer) setConn(c serverConn) { | |
38 | w.mu.Lock() | |
39 | w.conn = c | |
40 | w.mu.Unlock() | |
41 | } | |
42 | ||
24 | 43 | // connect makes a connection to the syslog server. |
25 | // It must be called with w.mu held. | |
26 | func (w *Writer) connect() (err error) { | |
27 | if w.conn != nil { | |
44 | func (w *Writer) connect() (serverConn, error) { | |
45 | conn := w.getConn() | |
46 | if conn != nil { | |
28 | 47 | // ignore err from close, it makes sense to continue anyway |
29 | w.conn.close() | |
30 | w.conn = nil | |
31 | } | |
32 | ||
33 | var conn serverConn | |
48 | conn.close() | |
49 | w.setConn(nil) | |
50 | } | |
51 | ||
34 | 52 | var hostname string |
53 | var err error | |
35 | 54 | dialer := w.getDialer() |
36 | 55 | conn, hostname, err = dialer.Call() |
37 | 56 | if err == nil { |
38 | w.conn = conn | |
57 | w.setConn(conn) | |
39 | 58 | w.hostname = hostname |
40 | } | |
41 | ||
42 | return | |
59 | ||
60 | return conn, nil | |
61 | } else { | |
62 | return nil, err | |
63 | } | |
43 | 64 | } |
44 | 65 | |
45 | 66 | // SetFormatter changes the formatter function for subsequent messages. |
50 | 71 | // SetFramer changes the framer function for subsequent messages. |
51 | 72 | func (w *Writer) SetFramer(f Framer) { |
52 | 73 | w.framer = f |
74 | } | |
75 | ||
76 | // SetHostname changes the hostname for syslog messages if needed. | |
77 | func (w *Writer) SetHostname(hostname string) { | |
78 | w.hostname = hostname | |
53 | 79 | } |
54 | 80 | |
55 | 81 | // Write sends a log message to the syslog daemon using the default priority |
58 | 84 | return w.writeAndRetry(w.priority, string(b)) |
59 | 85 | } |
60 | 86 | |
87 | // WriteWithPriority sends a log message with a custom priority. | |
88 | func (w *Writer) WriteWithPriority(p Priority, b []byte) (int, error) { | |
89 | return w.writeAndRetryWithPriority(p, string(b)) | |
90 | } | |
91 | ||
61 | 92 | // Close closes a connection to the syslog daemon. |
62 | 93 | func (w *Writer) Close() error { |
63 | w.Lock() | |
64 | defer w.Unlock() | |
65 | ||
66 | if w.conn != nil { | |
67 | err := w.conn.close() | |
68 | w.conn = nil | |
94 | conn := w.getConn() | |
95 | if conn != nil { | |
96 | err := conn.close() | |
97 | w.setConn(nil) | |
69 | 98 | return err |
70 | 99 | } |
71 | 100 | return nil |
127 | 156 | return err |
128 | 157 | } |
129 | 158 | |
130 | func (w *Writer) writeAndRetry(p Priority, s string) (int, error) { | |
131 | pr := (w.priority & facilityMask) | (p & severityMask) | |
132 | ||
133 | w.Lock() | |
134 | defer w.Unlock() | |
135 | ||
136 | if w.conn != nil { | |
137 | if n, err := w.write(pr, s); err == nil { | |
159 | // writeAndRetry takes a severity and the string to write. Any facility passed to | |
160 | // it as part of the severity Priority will be ignored. | |
161 | func (w *Writer) writeAndRetry(severity Priority, s string) (int, error) { | |
162 | pr := (w.priority & facilityMask) | (severity & severityMask) | |
163 | ||
164 | return w.writeAndRetryWithPriority(pr, s) | |
165 | } | |
166 | ||
167 | // writeAndRetryWithPriority differs from writeAndRetry in that it allows setting | |
168 | // of both the facility and the severity. | |
169 | func (w *Writer) writeAndRetryWithPriority(p Priority, s string) (int, error) { | |
170 | conn := w.getConn() | |
171 | if conn != nil { | |
172 | if n, err := w.write(conn, p, s); err == nil { | |
138 | 173 | return n, err |
139 | 174 | } |
140 | 175 | } |
141 | if err := w.connect(); err != nil { | |
176 | ||
177 | var err error | |
178 | if conn, err = w.connect(); err != nil { | |
142 | 179 | return 0, err |
143 | 180 | } |
144 | return w.write(pr, s) | |
181 | return w.write(conn, p, s) | |
145 | 182 | } |
146 | 183 | |
147 | 184 | // write generates and writes a syslog formatted string. It formats the |
148 | 185 | // message based on the current Formatter and Framer. |
149 | func (w *Writer) write(p Priority, msg string) (int, error) { | |
186 | func (w *Writer) write(conn serverConn, p Priority, msg string) (int, error) { | |
150 | 187 | // ensure it ends in a \n |
151 | 188 | if !strings.HasSuffix(msg, "\n") { |
152 | 189 | msg += "\n" |
153 | 190 | } |
154 | 191 | |
155 | err := w.conn.writeString(w.framer, w.formatter, p, w.hostname, w.tag, msg) | |
192 | err := conn.writeString(w.framer, w.formatter, p, w.hostname, w.tag, msg) | |
156 | 193 | if err != nil { |
157 | 194 | return 0, err |
158 | 195 | } |
23 | 23 | if n != 0 { |
24 | 24 | t.Errorf("should not write any bytes") |
25 | 25 | } |
26 | } | |
27 | ||
28 | func TestSetHostname(t *testing.T) { | |
29 | customHostname := "kubernetesCluster" | |
30 | expected := customHostname | |
31 | ||
32 | done := make(chan string) | |
33 | addr, sock, srvWG := startServer("udp", "", done) | |
34 | defer sock.Close() | |
35 | defer srvWG.Wait() | |
36 | ||
37 | w := Writer{ | |
38 | priority: LOG_ERR, | |
39 | network: "udp", | |
40 | raddr: addr, | |
41 | } | |
42 | ||
43 | _, err := w.connect() | |
44 | if err != nil { | |
45 | t.Errorf("failed to connect: %v", err) | |
46 | } | |
47 | defer w.Close() | |
48 | ||
49 | if strings.Split(w.hostname, ":")[0] != "127.0.0.1" { | |
50 | t.Errorf("expected hostname: %s, got %s", "127.0.0.1", strings.Split(w.hostname, ":")[0]) | |
51 | } | |
52 | ||
53 | w.SetHostname(customHostname) | |
54 | if w.hostname != expected { | |
55 | t.Errorf("expected hostname: %s, got %s", expected, w.hostname) | |
56 | } | |
57 | <-done | |
26 | 58 | } |
27 | 59 | |
28 | 60 | func TestWriteFormatters(t *testing.T) { |
51 | 83 | raddr: addr, |
52 | 84 | } |
53 | 85 | |
54 | w.Lock() | |
55 | err := w.connect() | |
86 | _, err := w.connect() | |
56 | 87 | if err != nil { |
57 | 88 | t.Errorf("failed to connect: %v", err) |
58 | w.Unlock() | |
59 | } | |
60 | w.Unlock() | |
89 | } | |
61 | 90 | defer w.Close() |
62 | 91 | |
63 | 92 | w.SetFormatter(test.f) |
103 | 132 | raddr: addr, |
104 | 133 | } |
105 | 134 | |
106 | w.Lock() | |
107 | err := w.connect() | |
135 | _, err := w.connect() | |
108 | 136 | if err != nil { |
109 | 137 | t.Errorf("failed to connect: %v", err) |
110 | w.Unlock() | |
111 | } | |
112 | w.Unlock() | |
138 | } | |
113 | 139 | defer w.Close() |
114 | 140 | |
115 | 141 | w.SetFramer(test.f) |
131 | 157 | } |
132 | 158 | } |
133 | 159 | |
160 | func TestWriteWithDefaultPriority(t *testing.T) { | |
161 | done := make(chan string) | |
162 | addr, sock, srvWG := startServer("udp", "", done) | |
163 | defer sock.Close() | |
164 | defer srvWG.Wait() | |
165 | ||
166 | w := Writer{ | |
167 | priority: LOG_ERR, | |
168 | tag: "tag", | |
169 | hostname: "hostname", | |
170 | network: "udp", | |
171 | raddr: addr, | |
172 | } | |
173 | ||
174 | _, err := w.connect() | |
175 | if err != nil { | |
176 | t.Errorf("failed to connect: %v", err) | |
177 | } | |
178 | defer w.Close() | |
179 | ||
180 | var bytes int | |
181 | bytes, err = w.Write([]byte("this is a test message")) | |
182 | if err != nil { | |
183 | t.Errorf("failed to write: %v", err) | |
184 | } | |
185 | if bytes == 0 { | |
186 | t.Errorf("zero bytes written") | |
187 | } | |
188 | ||
189 | checkWithPriorityAndTag(t, LOG_ERR, "tag", "hostname", "this is a test message", <-done) | |
190 | } | |
191 | ||
192 | func TestWriteWithPriority(t *testing.T) { | |
193 | done := make(chan string) | |
194 | addr, sock, srvWG := startServer("udp", "", done) | |
195 | defer sock.Close() | |
196 | defer srvWG.Wait() | |
197 | ||
198 | w := Writer{ | |
199 | priority: LOG_ERR, | |
200 | tag: "tag", | |
201 | hostname: "hostname", | |
202 | network: "udp", | |
203 | raddr: addr, | |
204 | } | |
205 | ||
206 | _, err := w.connect() | |
207 | if err != nil { | |
208 | t.Errorf("failed to connect: %v", err) | |
209 | } | |
210 | defer w.Close() | |
211 | ||
212 | var bytes int | |
213 | bytes, err = w.WriteWithPriority(LOG_DEBUG, []byte("this is a test message")) | |
214 | if err != nil { | |
215 | t.Errorf("failed to write: %v", err) | |
216 | } | |
217 | if bytes == 0 { | |
218 | t.Errorf("zero bytes written") | |
219 | } | |
220 | ||
221 | checkWithPriorityAndTag(t, LOG_DEBUG, "tag", "hostname", "this is a test message", <-done) | |
222 | } | |
223 | ||
224 | func TestWriteWithPriorityAndFacility(t *testing.T) { | |
225 | done := make(chan string) | |
226 | addr, sock, srvWG := startServer("udp", "", done) | |
227 | defer sock.Close() | |
228 | defer srvWG.Wait() | |
229 | ||
230 | w := Writer{ | |
231 | priority: LOG_ERR, | |
232 | tag: "tag", | |
233 | hostname: "hostname", | |
234 | network: "udp", | |
235 | raddr: addr, | |
236 | } | |
237 | ||
238 | _, err := w.connect() | |
239 | if err != nil { | |
240 | t.Errorf("failed to connect: %v", err) | |
241 | } | |
242 | defer w.Close() | |
243 | ||
244 | var bytes int | |
245 | bytes, err = w.WriteWithPriority(LOG_DEBUG|LOG_LOCAL5, []byte("this is a test message")) | |
246 | if err != nil { | |
247 | t.Errorf("failed to write: %v", err) | |
248 | } | |
249 | if bytes == 0 { | |
250 | t.Errorf("zero bytes written") | |
251 | } | |
252 | ||
253 | checkWithPriorityAndTag(t, LOG_DEBUG|LOG_LOCAL5, "tag", "hostname", "this is a test message", <-done) | |
254 | } | |
255 | ||
134 | 256 | func TestDebug(t *testing.T) { |
135 | 257 | done := make(chan string) |
136 | 258 | addr, sock, srvWG := startServer("udp", "", done) |
145 | 267 | raddr: addr, |
146 | 268 | } |
147 | 269 | |
148 | w.Lock() | |
149 | err := w.connect() | |
150 | if err != nil { | |
151 | t.Errorf("failed to connect: %v", err) | |
152 | w.Unlock() | |
153 | } | |
154 | w.Unlock() | |
270 | _, err := w.connect() | |
271 | if err != nil { | |
272 | t.Errorf("failed to connect: %v", err) | |
273 | } | |
155 | 274 | defer w.Close() |
156 | 275 | |
157 | 276 | err = w.Debug("this is a test message") |
176 | 295 | raddr: addr, |
177 | 296 | } |
178 | 297 | |
179 | w.Lock() | |
180 | err := w.connect() | |
181 | if err != nil { | |
182 | t.Errorf("failed to connect: %v", err) | |
183 | w.Unlock() | |
184 | } | |
185 | w.Unlock() | |
298 | _, err := w.connect() | |
299 | if err != nil { | |
300 | t.Errorf("failed to connect: %v", err) | |
301 | } | |
186 | 302 | defer w.Close() |
187 | 303 | |
188 | 304 | err = w.Info("this is a test message") |
207 | 323 | raddr: addr, |
208 | 324 | } |
209 | 325 | |
210 | w.Lock() | |
211 | err := w.connect() | |
212 | if err != nil { | |
213 | t.Errorf("failed to connect: %v", err) | |
214 | w.Unlock() | |
215 | } | |
216 | w.Unlock() | |
326 | _, err := w.connect() | |
327 | if err != nil { | |
328 | t.Errorf("failed to connect: %v", err) | |
329 | } | |
217 | 330 | defer w.Close() |
218 | 331 | |
219 | 332 | err = w.Notice("this is a test message") |
238 | 351 | raddr: addr, |
239 | 352 | } |
240 | 353 | |
241 | w.Lock() | |
242 | err := w.connect() | |
243 | if err != nil { | |
244 | t.Errorf("failed to connect: %v", err) | |
245 | w.Unlock() | |
246 | } | |
247 | w.Unlock() | |
354 | _, err := w.connect() | |
355 | if err != nil { | |
356 | t.Errorf("failed to connect: %v", err) | |
357 | } | |
248 | 358 | defer w.Close() |
249 | 359 | |
250 | 360 | err = w.Warning("this is a test message") |
269 | 379 | raddr: addr, |
270 | 380 | } |
271 | 381 | |
272 | w.Lock() | |
273 | err := w.connect() | |
274 | if err != nil { | |
275 | t.Errorf("failed to connect: %v", err) | |
276 | w.Unlock() | |
277 | } | |
278 | w.Unlock() | |
382 | _, err := w.connect() | |
383 | if err != nil { | |
384 | t.Errorf("failed to connect: %v", err) | |
385 | } | |
279 | 386 | defer w.Close() |
280 | 387 | |
281 | 388 | err = w.Err("this is a test message") |
300 | 407 | raddr: addr, |
301 | 408 | } |
302 | 409 | |
303 | w.Lock() | |
304 | err := w.connect() | |
305 | if err != nil { | |
306 | t.Errorf("failed to connect: %v", err) | |
307 | w.Unlock() | |
308 | } | |
309 | w.Unlock() | |
410 | _, err := w.connect() | |
411 | if err != nil { | |
412 | t.Errorf("failed to connect: %v", err) | |
413 | } | |
310 | 414 | defer w.Close() |
311 | 415 | |
312 | 416 | err = w.Crit("this is a test message") |
331 | 435 | raddr: addr, |
332 | 436 | } |
333 | 437 | |
334 | w.Lock() | |
335 | err := w.connect() | |
336 | if err != nil { | |
337 | t.Errorf("failed to connect: %v", err) | |
338 | w.Unlock() | |
339 | } | |
340 | w.Unlock() | |
438 | _, err := w.connect() | |
439 | if err != nil { | |
440 | t.Errorf("failed to connect: %v", err) | |
441 | } | |
341 | 442 | defer w.Close() |
342 | 443 | |
343 | 444 | err = w.Alert("this is a test message") |
362 | 463 | raddr: addr, |
363 | 464 | } |
364 | 465 | |
365 | w.Lock() | |
366 | err := w.connect() | |
367 | if err != nil { | |
368 | t.Errorf("failed to connect: %v", err) | |
369 | w.Unlock() | |
370 | } | |
371 | w.Unlock() | |
466 | _, err := w.connect() | |
467 | if err != nil { | |
468 | t.Errorf("failed to connect: %v", err) | |
469 | } | |
372 | 470 | defer w.Close() |
373 | 471 | |
374 | 472 | err = w.Emerg("this is a test message") |