Browse code

Vendor new syslog library with TLS support.

The syslog package in the stdlib is not maintained anymore.

Signed-off-by: David Calavera <david.calavera@gmail.com>

David Calavera authored on 2016/01/09 02:35:35
Showing 12 changed files
... ...
@@ -23,6 +23,7 @@ clone git golang.org/x/net 47990a1ba55743e6ef1affd3a14e5bac8553615d https://gith
23 23
 clone git github.com/docker/go-units 651fc226e7441360384da338d0fd37f2440ffbe3
24 24
 clone git github.com/docker/go-connections v0.1.2
25 25
 clone git github.com/docker/engine-api v0.1.3
26
+clone git github.com/RackSec/srslog 6eb773f331e46fbba8eecb8e794e635e75fc04de
26 27
 
27 28
 #get libnetwork packages
28 29
 clone git github.com/docker/libnetwork 9f0563ea8f430d8828553aac97161cbff4056436
29 30
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+.cover
0 1
new file mode 100644
... ...
@@ -0,0 +1,13 @@
0
+sudo: required
1
+dist: trusty
2
+group: edge
3
+language: go
4
+go:
5
+- 1.5
6
+script:
7
+- |
8
+  go get ./...
9
+  go test -v ./...
10
+notifications:
11
+  slack:
12
+    secure: dtDue9gP6CRR1jYjEf6raXXFak3QKGcCFvCf5mfvv5XScdpmc3udwgqc5TdyjC0goaC9OK/4jTcCD30dYZm/u6ux3E9mo3xwMl2xRLHx76p5r9rSQtloH19BDwA2+A+bpDfFQVz05k2YXuTiGSvNMMdwzx+Dr294Sl/z43RFB4+b9/R/6LlFpRW89IwftvpLAFnBy4K/ZcspQzKM+rQfQTL5Kk+iZ/KBsuR/VziDq6MoJ8t43i4ee8vwS06vFBKDbUiZ4FIZpLgc2RAL5qso5aWRKYXL6waXfoKHZWKPe0w4+9IY1rDJxG1jEb7YGgcbLaF9xzPRRs2b2yO/c87FKpkh6PDgYHfLjpgXotCoojZrL4p1x6MI1ldJr3NhARGPxS9r4liB9n6Y5nD+ErXi1IMf55fuUHcPY27Jc0ySeLFeM6cIWJ8OhFejCgGw6a5DnnmJo0PqopsaBDHhadpLejT1+K6bL2iGkT4SLcVNuRGLs+VyuNf1+5XpkWZvy32vquO7SZOngLLBv+GIem+t3fWm0Z9s/0i1uRCQei1iUutlYjoV/LBd35H2rhob4B5phIuJin9kb0zbHf6HnaoN0CtN8r0d8G5CZiInVlG5Xcid5Byb4dddf5U2EJTDuCMVyyiM7tcnfjqw9UbVYNxtYM9SzcqIq+uVqM8pYL9xSec=
0 13
new file mode 100644
... ...
@@ -0,0 +1,50 @@
0
+# Contributor Code of Conduct
1
+
2
+As contributors and maintainers of this project, and in the interest of
3
+fostering an open and welcoming community, we pledge to respect all people who
4
+contribute through reporting issues, posting feature requests, updating
5
+documentation, submitting pull requests or patches, and other activities.
6
+
7
+We are committed to making participation in this project a harassment-free
8
+experience for everyone, regardless of level of experience, gender, gender
9
+identity and expression, sexual orientation, disability, personal appearance,
10
+body size, race, ethnicity, age, religion, or nationality.
11
+
12
+Examples of unacceptable behavior by participants include:
13
+
14
+* The use of sexualized language or imagery
15
+* Personal attacks
16
+* Trolling or insulting/derogatory comments
17
+* Public or private harassment
18
+* Publishing other's private information, such as physical or electronic
19
+  addresses, without explicit permission
20
+* Other unethical or unprofessional conduct
21
+
22
+Project maintainers have the right and responsibility to remove, edit, or
23
+reject comments, commits, code, wiki edits, issues, and other contributions
24
+that are not aligned to this Code of Conduct, or to ban temporarily or
25
+permanently any contributor for other behaviors that they deem inappropriate,
26
+threatening, offensive, or harmful.
27
+
28
+By adopting this Code of Conduct, project maintainers commit themselves to
29
+fairly and consistently applying these principles to every aspect of managing
30
+this project. Project maintainers who do not follow or enforce the Code of
31
+Conduct may be permanently removed from the project team.
32
+
33
+This Code of Conduct applies both within project spaces and in public spaces
34
+when an individual is representing the project or its community.
35
+
36
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
37
+reported by contacting a project maintainer at [sirsean@gmail.com]. All
38
+complaints will be reviewed and investigated and will result in a response that
39
+is deemed necessary and appropriate to the circumstances. Maintainers are
40
+obligated to maintain confidentiality with regard to the reporter of an
41
+incident.
42
+
43
+
44
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+version 1.3.0, available at
46
+[http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+[homepage]: http://contributor-covenant.org
49
+[version]: http://contributor-covenant.org/version/1/3/0/
0 50
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+Copyright (c) 2015 Rackspace. All rights reserved.
1
+
2
+Redistribution and use in source and binary forms, with or without
3
+modification, are permitted provided that the following conditions are
4
+met:
5
+
6
+   * Redistributions of source code must retain the above copyright
7
+notice, this list of conditions and the following disclaimer.
8
+   * Redistributions in binary form must reproduce the above
9
+copyright notice, this list of conditions and the following disclaimer
10
+in the documentation and/or other materials provided with the
11
+distribution.
12
+   * Neither the name of Google Inc. nor the names of its
13
+contributors may be used to endorse or promote products derived from
14
+this software without specific prior written permission.
15
+
16
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0 27
new file mode 100644
... ...
@@ -0,0 +1,131 @@
0
+[![Build Status](https://travis-ci.org/RackSec/srslog.svg?branch=master)](https://travis-ci.org/RackSec/srslog)
1
+
2
+# srslog
3
+
4
+Go has a `syslog` package in the standard library, but it has the following
5
+shortcomings:
6
+
7
+1. It doesn't have TLS support
8
+2. [According to bradfitz on the Go team, it is no longer being maintained.](https://github.com/golang/go/issues/13449#issuecomment-161204716)
9
+
10
+I agree that it doesn't need to be in the standard library. So, I've
11
+followed Brad's suggestion and have made a separate project to handle syslog.
12
+
13
+This code was taken directly from the Go project as a base to start from.
14
+
15
+However, this _does_ have TLS support.
16
+
17
+# Usage
18
+
19
+Basic usage retains the same interface as the original `syslog` package. We
20
+only added to the interface where required to support new functionality.
21
+
22
+Switch from the standard library:
23
+
24
+```
25
+import(
26
+    //"log/syslog"
27
+    syslog "github.com/RackSec/srslog"
28
+)
29
+```
30
+
31
+You can still use it for local syslog:
32
+
33
+```
34
+w, err := syslog.Dial("", "", syslog.LOG_ERR, "testtag")
35
+```
36
+
37
+Or to unencrypted UDP:
38
+
39
+```
40
+w, err := syslog.Dial("udp", "192.168.0.50:514", syslog.LOG_ERR, "testtag")
41
+```
42
+
43
+Or to unencrypted TCP:
44
+
45
+```
46
+w, err := syslog.Dial("tcp", "192.168.0.51:514", syslog.LOG_ERR, "testtag")
47
+```
48
+
49
+But now you can also send messages via TLS-encrypted TCP:
50
+
51
+```
52
+w, err := syslog.DialWithTLSCertPath("tcp+tls", "192.168.0.52:514", syslog.LOG_ERR, "testtag", "/path/to/servercert.pem")
53
+```
54
+
55
+And if you need more control over your TLS configuration :
56
+
57
+```
58
+pool := x509.NewCertPool()
59
+serverCert, err := ioutil.ReadFile("/path/to/servercert.pem")
60
+if err != nil {
61
+    return nil, err
62
+}
63
+pool.AppendCertsFromPEM(serverCert)
64
+config := tls.Config{
65
+    RootCAs: pool,
66
+}
67
+
68
+w, err := DialWithTLSConfig(network, raddr, priority, tag, &config)
69
+```
70
+
71
+(Note that in both TLS cases, this uses a self-signed certificate, where the
72
+remote syslog server has the keypair and the client has only the public key.)
73
+
74
+And then to write log messages, continue like so:
75
+
76
+```
77
+if err != nil {
78
+    log.Fatal("failed to connect to syslog:", err)
79
+}
80
+defer w.Close()
81
+
82
+w.Alert("this is an alert")
83
+w.Crit("this is critical")
84
+w.Err("this is an error")
85
+w.Warning("this is a warning")
86
+w.Notice("this is a notice")
87
+w.Info("this is info")
88
+w.Debug("this is debug")
89
+w.Write([]byte("these are some bytes"))
90
+```
91
+
92
+# Generating TLS Certificates
93
+
94
+We've provided a script that you can use to generate a self-signed keypair:
95
+
96
+```
97
+pip install cryptography
98
+python script/gen-certs.py
99
+```
100
+
101
+That outputs the public key and private key to standard out. Put those into
102
+`.pem` files. (And don't put them into any source control. The certificate in
103
+the `test` directory is used by the unit tests, and please do not actually use
104
+it anywhere else.)
105
+
106
+# Running Tests
107
+
108
+Run the tests as usual:
109
+
110
+```
111
+go test
112
+```
113
+
114
+But we've also provided a test coverage script that will show you which
115
+lines of code are not covered:
116
+
117
+```
118
+script/coverage --html
119
+```
120
+
121
+That will open a new browser tab showing coverage information.
122
+
123
+# License
124
+
125
+This project uses the New BSD License, the same as the Go project itself.
126
+
127
+# Code of Conduct
128
+
129
+Please note that this project is released with a Contributor Code of Conduct.
130
+By participating in this project you agree to abide by its terms.
0 131
new file mode 100644
... ...
@@ -0,0 +1,68 @@
0
+package srslog
1
+
2
+import (
3
+	"errors"
4
+)
5
+
6
+// Priority is a combination of the syslog facility and
7
+// severity. For example, LOG_ALERT | LOG_FTP sends an alert severity
8
+// message from the FTP facility. The default severity is LOG_EMERG;
9
+// the default facility is LOG_KERN.
10
+type Priority int
11
+
12
+const severityMask = 0x07
13
+const facilityMask = 0xf8
14
+
15
+const (
16
+	// Severity.
17
+
18
+	// From /usr/include/sys/syslog.h.
19
+	// These are the same on Linux, BSD, and OS X.
20
+	LOG_EMERG Priority = iota
21
+	LOG_ALERT
22
+	LOG_CRIT
23
+	LOG_ERR
24
+	LOG_WARNING
25
+	LOG_NOTICE
26
+	LOG_INFO
27
+	LOG_DEBUG
28
+)
29
+
30
+const (
31
+	// Facility.
32
+
33
+	// From /usr/include/sys/syslog.h.
34
+	// These are the same up to LOG_FTP on Linux, BSD, and OS X.
35
+	LOG_KERN Priority = iota << 3
36
+	LOG_USER
37
+	LOG_MAIL
38
+	LOG_DAEMON
39
+	LOG_AUTH
40
+	LOG_SYSLOG
41
+	LOG_LPR
42
+	LOG_NEWS
43
+	LOG_UUCP
44
+	LOG_CRON
45
+	LOG_AUTHPRIV
46
+	LOG_FTP
47
+	_ // unused
48
+	_ // unused
49
+	_ // unused
50
+	_ // unused
51
+	LOG_LOCAL0
52
+	LOG_LOCAL1
53
+	LOG_LOCAL2
54
+	LOG_LOCAL3
55
+	LOG_LOCAL4
56
+	LOG_LOCAL5
57
+	LOG_LOCAL6
58
+	LOG_LOCAL7
59
+)
60
+
61
+func validatePriority(p Priority) error {
62
+	if p < 0 || p > LOG_LOCAL7|LOG_DEBUG {
63
+		return errors.New("log/syslog: invalid priority")
64
+	} else {
65
+		return nil
66
+	}
67
+}
0 68
new file mode 100644
... ...
@@ -0,0 +1,53 @@
0
+package srslog
1
+
2
+import (
3
+	"crypto/tls"
4
+	"net"
5
+)
6
+
7
+func (w Writer) getDialer() func() (serverConn, string, error) {
8
+	dialers := map[string]func() (serverConn, string, error){
9
+		"":        w.unixDialer,
10
+		"tcp+tls": w.tlsDialer,
11
+	}
12
+	dialer, ok := dialers[w.network]
13
+	if !ok {
14
+		dialer = w.basicDialer
15
+	}
16
+	return dialer
17
+}
18
+
19
+func (w Writer) unixDialer() (serverConn, string, error) {
20
+	sc, err := unixSyslog()
21
+	hostname := w.hostname
22
+	if hostname == "" {
23
+		hostname = "localhost"
24
+	}
25
+	return sc, hostname, err
26
+}
27
+
28
+func (w Writer) tlsDialer() (serverConn, string, error) {
29
+	c, err := tls.Dial("tcp", w.raddr, w.tlsConfig)
30
+	var sc serverConn
31
+	hostname := w.hostname
32
+	if err == nil {
33
+		sc = &netConn{conn: c}
34
+		if hostname == "" {
35
+			hostname = c.LocalAddr().String()
36
+		}
37
+	}
38
+	return sc, hostname, err
39
+}
40
+
41
+func (w Writer) basicDialer() (serverConn, string, error) {
42
+	c, err := net.Dial(w.network, w.raddr)
43
+	var sc serverConn
44
+	hostname := w.hostname
45
+	if err == nil {
46
+		sc = &netConn{conn: c}
47
+		if hostname == "" {
48
+			hostname = c.LocalAddr().String()
49
+		}
50
+	}
51
+	return sc, hostname, err
52
+}
0 53
new file mode 100644
... ...
@@ -0,0 +1,24 @@
0
+package srslog
1
+
2
+import (
3
+	"fmt"
4
+	"net"
5
+	"os"
6
+	"time"
7
+)
8
+
9
+type netConn struct {
10
+	conn net.Conn
11
+}
12
+
13
+func (n *netConn) writeString(p Priority, hostname, tag, msg string) error {
14
+	timestamp := time.Now().Format(time.RFC3339)
15
+	_, err := fmt.Fprintf(n.conn, "<%d>%s %s %s[%d]: %s",
16
+		p, timestamp, hostname,
17
+		tag, os.Getpid(), msg)
18
+	return err
19
+}
20
+
21
+func (n *netConn) close() error {
22
+	return n.conn.Close()
23
+}
0 24
new file mode 100644
... ...
@@ -0,0 +1,96 @@
0
+package srslog
1
+
2
+import (
3
+	"crypto/tls"
4
+	"crypto/x509"
5
+	"io/ioutil"
6
+	"log"
7
+	"os"
8
+)
9
+
10
+// This interface and the separate syslog_unix.go file exist for
11
+// Solaris support as implemented by gccgo.  On Solaris you can not
12
+// simply open a TCP connection to the syslog daemon.  The gccgo
13
+// sources have a syslog_solaris.go file that implements unixSyslog to
14
+// return a type that satisfies this interface and simply calls the C
15
+// library syslog function.
16
+type serverConn interface {
17
+	writeString(p Priority, hostname, tag, s string) error
18
+	close() error
19
+}
20
+
21
+// New establishes a new connection to the system log daemon.  Each
22
+// write to the returned Writer sends a log message with the given
23
+// priority and prefix.
24
+func New(priority Priority, tag string) (w *Writer, err error) {
25
+	return Dial("", "", priority, tag)
26
+}
27
+
28
+// Dial establishes a connection to a log daemon by connecting to
29
+// address raddr on the specified network.  Each write to the returned
30
+// Writer sends a log message with the given facility, severity and
31
+// tag.
32
+// If network is empty, Dial will connect to the local syslog server.
33
+func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) {
34
+	return DialWithTLSConfig(network, raddr, priority, tag, nil)
35
+}
36
+
37
+// DialWithTLSCertPath establishes a secure connection to a log daemon by connecting to
38
+// address raddr on the specified network. It uses certPath to load TLS certificates and configure
39
+// the secure connection.
40
+func DialWithTLSCertPath(network, raddr string, priority Priority, tag, certPath string) (*Writer, error) {
41
+	pool := x509.NewCertPool()
42
+	serverCert, err := ioutil.ReadFile(certPath)
43
+	if err != nil {
44
+		return nil, err
45
+	}
46
+	pool.AppendCertsFromPEM(serverCert)
47
+	config := tls.Config{
48
+		RootCAs: pool,
49
+	}
50
+
51
+	return DialWithTLSConfig(network, raddr, priority, tag, &config)
52
+}
53
+
54
+// DialWithTLSConfig establishes a secure connection to a log daemon by connecting to
55
+// address raddr on the specified network. It uses tlsConfig to configure the secure connection.
56
+func DialWithTLSConfig(network, raddr string, priority Priority, tag string, tlsConfig *tls.Config) (*Writer, error) {
57
+	if err := validatePriority(priority); err != nil {
58
+		return nil, err
59
+	}
60
+
61
+	if tag == "" {
62
+		tag = os.Args[0]
63
+	}
64
+	hostname, _ := os.Hostname()
65
+
66
+	w := &Writer{
67
+		priority:  priority,
68
+		tag:       tag,
69
+		hostname:  hostname,
70
+		network:   network,
71
+		raddr:     raddr,
72
+		tlsConfig: tlsConfig,
73
+	}
74
+
75
+	w.Lock()
76
+	defer w.Unlock()
77
+
78
+	err := w.connect()
79
+	if err != nil {
80
+		return nil, err
81
+	}
82
+	return w, err
83
+}
84
+
85
+// NewLogger creates a log.Logger whose output is written to
86
+// the system log service with the specified priority. The logFlag
87
+// argument is the flag set passed through to log.New to create
88
+// the Logger.
89
+func NewLogger(p Priority, logFlag int) (*log.Logger, error) {
90
+	s, err := New(p, "")
91
+	if err != nil {
92
+		return nil, err
93
+	}
94
+	return log.New(s, "", logFlag), nil
95
+}
0 96
new file mode 100644
... ...
@@ -0,0 +1,47 @@
0
+package srslog
1
+
2
+import (
3
+	"errors"
4
+	"fmt"
5
+	"net"
6
+	"os"
7
+	"time"
8
+)
9
+
10
+// unixSyslog opens a connection to the syslog daemon running on the
11
+// local machine using a Unix domain socket.
12
+
13
+func unixSyslog() (conn serverConn, err error) {
14
+	logTypes := []string{"unixgram", "unix"}
15
+	logPaths := []string{"/dev/log", "/var/run/syslog", "/var/run/log"}
16
+	for _, network := range logTypes {
17
+		for _, path := range logPaths {
18
+			conn, err := net.Dial(network, path)
19
+			if err != nil {
20
+				continue
21
+			} else {
22
+				return &localConn{conn: conn}, nil
23
+			}
24
+		}
25
+	}
26
+	return nil, errors.New("Unix syslog delivery error")
27
+}
28
+
29
+type localConn struct {
30
+	conn net.Conn
31
+}
32
+
33
+func (n *localConn) writeString(p Priority, hostname, tag, msg string) error {
34
+	// Compared to the network form at srslog.netConn, the changes are:
35
+	//	1. Use time.Stamp instead of time.RFC3339.
36
+	//	2. Drop the hostname field from the Fprintf.
37
+	timestamp := time.Now().Format(time.Stamp)
38
+	_, err := fmt.Fprintf(n.conn, "<%d>%s %s[%d]: %s",
39
+		p, timestamp,
40
+		tag, os.Getpid(), msg)
41
+	return err
42
+}
43
+
44
+func (n *localConn) close() error {
45
+	return n.conn.Close()
46
+}
0 47
new file mode 100644
... ...
@@ -0,0 +1,152 @@
0
+package srslog
1
+
2
+import (
3
+	"crypto/tls"
4
+	"strings"
5
+	"sync"
6
+)
7
+
8
+// A Writer is a connection to a syslog server.
9
+type Writer struct {
10
+	sync.Mutex // guards conn
11
+
12
+	priority  Priority
13
+	tag       string
14
+	hostname  string
15
+	network   string
16
+	raddr     string
17
+	tlsConfig *tls.Config
18
+
19
+	conn serverConn
20
+}
21
+
22
+// connect makes a connection to the syslog server.
23
+// It must be called with w.mu held.
24
+func (w *Writer) connect() (err error) {
25
+	if w.conn != nil {
26
+		// ignore err from close, it makes sense to continue anyway
27
+		w.conn.close()
28
+		w.conn = nil
29
+	}
30
+
31
+	var conn serverConn
32
+	var hostname string
33
+	dialer := w.getDialer()
34
+	conn, hostname, err = dialer()
35
+	if err == nil {
36
+		w.conn = conn
37
+		w.hostname = hostname
38
+	}
39
+
40
+	return
41
+}
42
+
43
+// Write sends a log message to the syslog daemon using the default priority
44
+// passed into `srslog.New` or the `srslog.Dial*` functions.
45
+func (w *Writer) Write(b []byte) (int, error) {
46
+	return w.writeAndRetry(w.priority, string(b))
47
+}
48
+
49
+// Close closes a connection to the syslog daemon.
50
+func (w *Writer) Close() error {
51
+	w.Lock()
52
+	defer w.Unlock()
53
+
54
+	if w.conn != nil {
55
+		err := w.conn.close()
56
+		w.conn = nil
57
+		return err
58
+	}
59
+	return nil
60
+}
61
+
62
+// Emerg logs a message with severity LOG_EMERG; this overrides the default
63
+// priority passed to `srslog.New` and the `srslog.Dial*` functions.
64
+func (w *Writer) Emerg(m string) (err error) {
65
+	_, err = w.writeAndRetry(LOG_EMERG, m)
66
+	return err
67
+}
68
+
69
+// Alert logs a message with severity LOG_ALERT; this overrides the default
70
+// priority passed to `srslog.New` and the `srslog.Dial*` functions.
71
+func (w *Writer) Alert(m string) (err error) {
72
+	_, err = w.writeAndRetry(LOG_ALERT, m)
73
+	return err
74
+}
75
+
76
+// Crit logs a message with severity LOG_CRIT; this overrides the default
77
+// priority passed to `srslog.New` and the `srslog.Dial*` functions.
78
+func (w *Writer) Crit(m string) (err error) {
79
+	_, err = w.writeAndRetry(LOG_CRIT, m)
80
+	return err
81
+}
82
+
83
+// Err logs a message with severity LOG_ERR; this overrides the default
84
+// priority passed to `srslog.New` and the `srslog.Dial*` functions.
85
+func (w *Writer) Err(m string) (err error) {
86
+	_, err = w.writeAndRetry(LOG_ERR, m)
87
+	return err
88
+}
89
+
90
+// Warning logs a message with severity LOG_WARNING; this overrides the default
91
+// priority passed to `srslog.New` and the `srslog.Dial*` functions.
92
+func (w *Writer) Warning(m string) (err error) {
93
+	_, err = w.writeAndRetry(LOG_WARNING, m)
94
+	return err
95
+}
96
+
97
+// Notice logs a message with severity LOG_NOTICE; this overrides the default
98
+// priority passed to `srslog.New` and the `srslog.Dial*` functions.
99
+func (w *Writer) Notice(m string) (err error) {
100
+	_, err = w.writeAndRetry(LOG_NOTICE, m)
101
+	return err
102
+}
103
+
104
+// Info logs a message with severity LOG_INFO; this overrides the default
105
+// priority passed to `srslog.New` and the `srslog.Dial*` functions.
106
+func (w *Writer) Info(m string) (err error) {
107
+	_, err = w.writeAndRetry(LOG_INFO, m)
108
+	return err
109
+}
110
+
111
+// Debug logs a message with severity LOG_DEBUG; this overrides the default
112
+// priority passed to `srslog.New` and the `srslog.Dial*` functions.
113
+func (w *Writer) Debug(m string) (err error) {
114
+	_, err = w.writeAndRetry(LOG_DEBUG, m)
115
+	return err
116
+}
117
+
118
+func (w *Writer) writeAndRetry(p Priority, s string) (int, error) {
119
+	pr := (w.priority & facilityMask) | (p & severityMask)
120
+
121
+	w.Lock()
122
+	defer w.Unlock()
123
+
124
+	if w.conn != nil {
125
+		if n, err := w.write(pr, s); err == nil {
126
+			return n, err
127
+		}
128
+	}
129
+	if err := w.connect(); err != nil {
130
+		return 0, err
131
+	}
132
+	return w.write(pr, s)
133
+}
134
+
135
+// write generates and writes a syslog formatted string. The
136
+// format is as follows: <PRI>TIMESTAMP HOSTNAME TAG[PID]: MSG
137
+func (w *Writer) write(p Priority, msg string) (int, error) {
138
+	// ensure it ends in a \n
139
+	if !strings.HasSuffix(msg, "\n") {
140
+		msg += "\n"
141
+	}
142
+
143
+	err := w.conn.writeString(p, w.hostname, w.tag, msg)
144
+	if err != nil {
145
+		return 0, err
146
+	}
147
+	// Note: return the length of the input, not the number of
148
+	// bytes printed by Fprintf, because this must behave like
149
+	// an io.Writer.
150
+	return len(msg), nil
151
+}