1 diff -r b0819469a6df src/pkg/syslog/syslog.go
2 --- a/src/pkg/syslog/syslog.go Thu Sep 08 12:16:42 2011 +1000
3 +++ b/src/pkg/syslog/syslog.go Tue Sep 20 11:29:08 2011 +1000
8 - // From /usr/include/sys/syslog.h.
9 - // These are the same on Linux, BSD, and OS X.
10 - LOG_EMERG Priority = iota
18 + // these are internal and are used to detect when overrides
20 + SeverityPresent = Priority(0x100)
21 + SeverityMask = Priority(0x7)
22 + FacilityPresent = Priority(0x200)
23 + FacilityMask = Priority(0x1f << 3)
25 + // From the RFCs. Names lifted from C.
26 + LOG_EMERG = Priority(0) | SeverityPresent
27 + LOG_ALERT = Priority(1) | SeverityPresent
28 + LOG_CRIT = Priority(2) | SeverityPresent
29 + LOG_ERR = Priority(3) | SeverityPresent
30 + LOG_WARNING = Priority(4) | SeverityPresent
31 + LOG_NOTICE = Priority(5) | SeverityPresent
32 + LOG_INFO = Priority(6) | SeverityPresent
33 + LOG_DEBUG = Priority(7) | SeverityPresent
35 + LOG_KERN = Priority(0<<3) | FacilityPresent
36 + LOG_USER = Priority(1<<3) | FacilityPresent
37 + LOG_MAIL = Priority(2<<3) | FacilityPresent
38 + LOG_DAEMON = Priority(3<<3) | FacilityPresent
39 + LOG_AUTH = Priority(4<<3) | FacilityPresent
40 + LOG_SYSLOG = Priority(5<<3) | FacilityPresent
41 + LOG_LPR = Priority(6<<3) | FacilityPresent
42 + LOG_NEWS = Priority(7<<3) | FacilityPresent
43 + LOG_UUCP = Priority(8<<3) | FacilityPresent
44 + LOG_CRON = Priority(9<<3) | FacilityPresent
45 + LOG_AUTHPRIV = Priority(10<<3) | FacilityPresent
46 + LOG_FTP = Priority(11<<3) | FacilityPresent
47 + LOG_LOCAL0 = Priority(16<<3) | FacilityPresent
48 + LOG_LOCAL1 = Priority(17<<3) | FacilityPresent
49 + LOG_LOCAL2 = Priority(18<<3) | FacilityPresent
50 + LOG_LOCAL3 = Priority(19<<3) | FacilityPresent
51 + LOG_LOCAL4 = Priority(20<<3) | FacilityPresent
52 + LOG_LOCAL5 = Priority(21<<3) | FacilityPresent
53 + LOG_LOCAL6 = Priority(22<<3) | FacilityPresent
54 + LOG_LOCAL7 = Priority(23<<3) | FacilityPresent
57 +// splicePriority takes origPri, and mixes in a severity or facility
58 +// if present in mixPri.
59 +func splicePriority(origPri, mixPri Priority) (newPri Priority) {
61 + if (mixPri & SeverityPresent) == SeverityPresent {
62 + newPri = (newPri & ^SeverityMask) | (mixPri & SeverityMask)
64 + if (mixPri & FacilityPresent) == FacilityPresent {
65 + newPri = (newPri & ^FacilityMask) | (mixPri & FacilityMask)
70 // A Writer is a connection to a syslog server.
75 + // persist the configured peer so we can reconnect when things really catch on fire.
80 type serverConn interface {
82 return Dial("", "", priority, prefix)
85 -// Dial establishes a connection to a log daemon by connecting
86 -// to address raddr on the network net.
87 +// Dial sets up a connection to a log daemon. The connection attempt
88 +// will be deferred until the first log message is sent.
89 // Each write to the returned writer sends a log message with
90 // the given priority and prefix.
91 +// If the prefix is empty, the binary's name - will be used in it's place.
92 func Dial(network, raddr string, priority Priority, prefix string) (w *Writer, err os.Error) {
98 - conn, err = unixSyslog()
99 + return &Writer{priority & 0xFF, prefix, nil, network, raddr}, err
102 +// Actually perform a real reconnect, closing any connections that may be open.
103 +func (w *Writer) Reconnect() (err os.Error) {
105 + log.Printf("writer.Reconnect() on old connection.\n")
109 + if w.network == "" {
110 + w.conn, err = unixSyslog()
113 - c, err = net.Dial(network, raddr)
115 + c, err = net.Dial(w.network, w.raddr)
116 + w.conn = &netConn{c}
118 - return &Writer{priority, prefix, conn}, err
122 +func canRetry(err os.Error) bool {
123 + // not an error? can't retry.
127 + oe, ok := err.(*net.OpError)
129 + if oe.Error == os.ECONNREFUSED {
136 // Write sends a log message to the syslog daemon.
137 -func (w *Writer) Write(b []byte) (int, os.Error) {
138 - if w.priority > LOG_DEBUG || w.priority < LOG_EMERG {
139 - return 0, os.EINVAL
140 +func (w *Writer) Write(b []byte) (bout int, err os.Error) {
142 + err = w.Reconnect()
147 - return w.conn.writeBytes(w.priority, w.prefix, b)
150 + bout, err = w.conn.writeBytes(w.priority, w.prefix, b)
152 + if canRetry(err) && !retried {
154 + err = w.Reconnect()
163 -func (w *Writer) writeString(p Priority, s string) (int, os.Error) {
164 - return w.conn.writeString(p, w.prefix, s)
165 +func (w *Writer) writeString(p Priority, s string) (bout int, err os.Error) {
166 + msgpriority := splicePriority(w.priority, p)
168 + err := w.Reconnect()
175 + bout, err = w.conn.writeString(msgpriority, w.prefix, s)
176 + if canRetry(err) && !retried {
177 + log.Printf("Retrying: %s", err)
178 + if err == os.ECONNREFUSED {
182 + err = w.Reconnect()
191 -func (w *Writer) Close() os.Error { return w.conn.close() }
192 +func (w *Writer) Close() os.Error {
194 + return w.conn.close()
199 // Emerg logs a message using the LOG_EMERG priority.
200 func (w *Writer) Emerg(m string) (err os.Error) {
201 @@ -124,15 +233,15 @@
205 -func (n netConn) writeBytes(p Priority, prefix string, b []byte) (int, os.Error) {
206 - return fmt.Fprintf(n.conn, "<%d>%s: %s\n", p, prefix, b)
207 +func (n *netConn) writeBytes(p Priority, prefix string, b []byte) (int, os.Error) {
208 + return fmt.Fprintf(n.conn, "<%d>%s: %s\n", p&0xFF, prefix, b)
211 -func (n netConn) writeString(p Priority, prefix string, s string) (int, os.Error) {
212 - return fmt.Fprintf(n.conn, "<%d>%s: %s\n", p, prefix, s)
213 +func (n *netConn) writeString(p Priority, prefix string, s string) (int, os.Error) {
214 + return fmt.Fprintf(n.conn, "<%d>%s: %s\n", p&0xFF, prefix, s)
217 -func (n netConn) close() os.Error {
218 +func (n *netConn) close() os.Error {
219 return n.conn.Close()
222 diff -r b0819469a6df src/pkg/syslog/syslog_test.go
223 --- a/src/pkg/syslog/syslog_test.go Thu Sep 08 12:16:42 2011 +1000
224 +++ b/src/pkg/syslog/syslog_test.go Tue Sep 20 11:29:08 2011 +1000
233 var serverAddr string
235 +const testSocketAddress = "/tmp/fakelog"
237 func runSyslog(c net.PacketConn, done chan<- string) {
242 rcvd += string(buf[0:n])
249 -func startServer(done chan<- string) {
250 +func startUDPServer(done chan<- string) {
251 c, e := net.ListenPacket("udp", "127.0.0.1:0")
253 log.Fatalf("net.ListenPacket failed udp :0 %v", e)
255 go runSyslog(c, done)
258 +func runUDPSyslog(c *net.UDPConn, done chan<- string) {
260 + var rcvd string = ""
262 + n, err := c.Read(buf[0:])
263 + if err != nil || n == 0 {
266 + rcvd += string(buf[0:n])
273 +func startUnixServer(done chan<- string) (ready <-chan int) {
274 + syslogready := make(chan int, 1)
275 + os.Remove(testSocketAddress)
276 + uaddr, e := net.ResolveUnixAddr("unixgram", testSocketAddress)
278 + log.Fatalf("net.ResolveUnixAddr failed: %v", e)
280 + c, e := net.ListenUnixgram("unixgram", uaddr)
282 + log.Fatalf("net.ListenPacket failed unixgram /tmp/fakelog %v", e)
285 + c.SetReadTimeout(1000e6) // 100ms
286 + go runUDPSyslog(c, done)
291 func skipNetTest(t *testing.T) bool {
293 // Depends on syslog daemon running, and sometimes it's not.
298 +func TestFakeUnixSyslog(t *testing.T) {
299 + done := make(chan string)
300 + startUnixServer(done)
301 + s, err := Dial("unixgram", "/tmp/fakelog", LOG_INFO|LOG_LOCAL0, "syslog_test")
303 + t.Fatalf("Dial() failed: %s", err)
305 + err = s.Debug("Moo")
307 + t.Fatalf("s.Debug() failed: %s", err)
309 + expected := "<135>syslog_test: Moo\n"
311 + if rcvd != expected {
312 + t.Fatalf("s.Debug() = '%q', but wanted '%q'", rcvd, expected)
317 +func TestFlap(t *testing.T) {
318 + done := make(chan string)
319 + startUnixServer(done)
320 + s, err := Dial("unixgram", "/tmp/fakelog", LOG_INFO|LOG_LOCAL0, "syslog_test")
322 + t.Fatalf("Dial() failed: %s", err)
324 + err = s.Debug("Moo")
326 + t.Fatalf("s.Debug() failed: %s", err)
328 + expected := "<135>syslog_test: Moo\n"
330 + if rcvd != expected {
331 + t.Fatalf("s.Debug() = '%q', but wanted '%q'", rcvd, expected)
333 + // restart the server.
334 + <-startUnixServer(done)
336 + // and try retransmitting.
337 + err = s.Debug("Re-Moo")
339 + t.Fatalf("s.Debug() failed: %s", err)
341 + expected = "<135>syslog_test: Re-Moo\n"
343 + if rcvd != expected {
344 + t.Fatalf("s.Info() = '%q', but wanted '%q'", rcvd, expected)
349 func TestNew(t *testing.T) {
354 func TestUDPDial(t *testing.T) {
355 done := make(chan string)
357 - l, err := Dial("udp", serverAddr, LOG_INFO, "syslog_test")
358 + startUDPServer(done)
359 + // it's important that the Dial priority is different to the
360 + // actual message sent - this tests priority splicing.
361 + l, err := Dial("udp", serverAddr, LOG_DEBUG, "syslog_test")
363 t.Fatalf("syslog.Dial() failed: %s", err)
367 func TestWrite(t *testing.T) {
368 done := make(chan string)
370 + startUDPServer(done)
371 l, err := Dial("udp", serverAddr, LOG_ERR, "syslog_test")
373 t.Fatalf("syslog.Dial() failed: %s", err)
374 diff -r b0819469a6df src/pkg/syslog/syslog_unix.go
375 --- a/src/pkg/syslog/syslog_unix.go Thu Sep 08 12:16:42 2011 +1000
376 +++ b/src/pkg/syslog/syslog_unix.go Tue Sep 20 11:29:08 2011 +1000
381 - return netConn{conn}, nil
382 + return &netConn{conn}, nil