The syslog package in the stdlib is not maintained anymore.
Signed-off-by: David Calavera <david.calavera@gmail.com>
| ... | ... |
@@ -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 |
| 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 |
+[](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 |
+} |