Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(20)

Delta Between Two Patch Sets: src/pkg/log/syslog/syslog.go

Issue 6782140: code review 6782140: log/syslog: retry once if write fails (Closed)
Left Patch Set: diff -r 025b9d070a85 https://code.google.com/p/go Created 12 years, 3 months ago
Right Patch Set: diff -r a9211b512258 http://code.google.com/p/go Created 12 years, 1 month ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | src/pkg/log/syslog/syslog_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 // Copyright 2012 The Go Authors. All rights reserved. 1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 // +build !windows,!plan9 5 // +build !windows,!plan9
6 6
7 // Package syslog provides a simple interface to the system log 7 // Package syslog provides a simple interface to the system log
8 // service. It can send messages to the syslog daemon using UNIX 8 // service. It can send messages to the syslog daemon using UNIX
9 // domain sockets, UDP, or TCP connections. 9 // domain sockets, UDP or TCP.
10 //
11 // Only one call to Dial is necessary. On write failures,
12 // the syslog client will attempt to reconnect to the server
13 // and write again.
10 package syslog 14 package syslog
11 15
12 import ( 16 import (
13 "errors" 17 "errors"
14 "fmt" 18 "fmt"
15 "log" 19 "log"
16 "net" 20 "net"
17 "os" 21 "os"
22 "strings"
23 "sync"
18 "time" 24 "time"
19 ) 25 )
20 26
21 // The Priority is a combination of the syslog facility and 27 // The Priority is a combination of the syslog facility and
22 // severity. For example, LOG_ALERT | LOG_FTP sends an alert severity 28 // severity. For example, LOG_ALERT | LOG_FTP sends an alert severity
23 // message from the FTP facility. The default severity is LOG_EMERG; 29 // message from the FTP facility. The default severity is LOG_EMERG;
24 // the default facility is LOG_KERN. 30 // the default facility is LOG_KERN.
25 type Priority int 31 type Priority int
26 32
27 const severityMask = 0x07 33 const severityMask = 0x07
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 LOG_LOCAL5 77 LOG_LOCAL5
72 LOG_LOCAL6 78 LOG_LOCAL6
73 LOG_LOCAL7 79 LOG_LOCAL7
74 ) 80 )
75 81
76 // A Writer is a connection to a syslog server. 82 // A Writer is a connection to a syslog server.
77 type Writer struct { 83 type Writer struct {
78 priority Priority 84 priority Priority
79 tag string 85 tag string
80 hostname string 86 hostname string
81 conn serverConn
82 network string 87 network string
83 raddr string 88 raddr string
84 } 89
85 90 » mu sync.Mutex // guards conn
86 type serverConn interface {
87 » writeString(p Priority, hostname, tag, s string) (int, error)
88 » close() error
89 }
90
91 type netConn struct {
92 conn net.Conn 91 conn net.Conn
93 } 92 }
94 93
95 // New establishes a new connection to the system log daemon. Each 94 // New establishes a new connection to the system log daemon. Each
96 // write to the returned writer sends a log message with the given 95 // write to the returned writer sends a log message with the given
97 // priority and prefix. 96 // priority and prefix.
98 func New(priority Priority, tag string) (w *Writer, err error) { 97 func New(priority Priority, tag string) (w *Writer, err error) {
99 return Dial("", "", priority, tag) 98 return Dial("", "", priority, tag)
100 } 99 }
101 100
102 // Dial establishes a connection to a log daemon by connecting to 101 // Dial establishes a connection to a log daemon by connecting to
103 // address raddr on the network net. Each write to the returned 102 // address raddr on the network net. Each write to the returned
104 // writer sends a log message with the given facility, severity and 103 // writer sends a log message with the given facility, severity and
105 // tag. 104 // tag.
106 func Dial(network, raddr string, priority Priority, tag string) (w *Writer, err error) { 105 func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) {
107 if priority < 0 || priority > LOG_LOCAL7|LOG_DEBUG { 106 if priority < 0 || priority > LOG_LOCAL7|LOG_DEBUG {
108 return nil, errors.New("log/syslog: invalid priority") 107 return nil, errors.New("log/syslog: invalid priority")
109 } 108 }
110 109
111 if tag == "" { 110 if tag == "" {
112 tag = os.Args[0] 111 tag = os.Args[0]
113 } 112 }
114
115 hostname, _ := os.Hostname() 113 hostname, _ := os.Hostname()
116 114
117 » return &Writer{priority: priority, tag: tag, hostname: hostname, conn: n il, network: network, raddr: raddr}, nil 115 » w := &Writer{
118 } 116 » » priority: priority,
119 117 » » tag: tag,
120 func (w *Writer) reconnect() (err error) { 118 » » hostname: hostname,
119 » » network: network,
120 » » raddr: raddr,
121 » }
122
123 » w.mu.Lock()
124 » defer w.mu.Unlock()
125
126 » err := w.connect()
127 » if err != nil {
128 » » return nil, err
129 » }
130 » return w, err
131 }
132
133 // connect makes a connection to the syslog server.
134 // It must be called with w.mu held.
135 func (w *Writer) connect() (err error) {
121 if w.conn != nil { 136 if w.conn != nil {
122 // ignore err from close, it makes sense to continue anyway 137 // ignore err from close, it makes sense to continue anyway
123 » » w.conn.close() 138 » » w.conn.Close()
139 » » w.conn = nil
124 } 140 }
125 141
126 if w.network == "" { 142 if w.network == "" {
127 w.conn, err = unixSyslog() 143 w.conn, err = unixSyslog()
128 if w.hostname == "" { 144 if w.hostname == "" {
129 w.hostname = "localhost" 145 w.hostname = "localhost"
130 } 146 }
131 } else { 147 } else {
132 var c net.Conn 148 var c net.Conn
133 c, err = net.Dial(w.network, w.raddr) 149 c, err = net.Dial(w.network, w.raddr)
134 if err == nil { 150 if err == nil {
135 » » » w.conn = netConn{c} 151 » » » w.conn = c
136 if w.hostname == "" { 152 if w.hostname == "" {
137 w.hostname = c.LocalAddr().String() 153 w.hostname = c.LocalAddr().String()
138 } 154 }
139 } 155 }
140 } 156 }
141 return 157 return
142 } 158 }
143 159
144 func shouldRetry(err error) bool {
145 if oe, ok := err.(*net.OpError); ok {
146 return oe.Refused()
147 }
148 return false
149 }
150
151 // Write sends a log message to the syslog daemon. 160 // Write sends a log message to the syslog daemon.
152 func (w *Writer) Write(b []byte) (int, error) { 161 func (w *Writer) Write(b []byte) (int, error) {
153 » return w.writeString(w.priority, string(b)) 162 » return w.writeAndRetry(w.priority, string(b))
154 } 163 }
155 164
165 // Close closes a connection to the syslog daemon.
156 func (w *Writer) Close() error { 166 func (w *Writer) Close() error {
167 w.mu.Lock()
168 defer w.mu.Unlock()
169
157 if w.conn != nil { 170 if w.conn != nil {
158 » » return w.conn.close() 171 » » err := w.conn.Close()
172 » » w.conn = nil
173 » » return err
159 } 174 }
160 return nil 175 return nil
161 } 176 }
162 177
163 // Emerg logs a message with severity LOG_EMERG, ignoring the severity 178 // Emerg logs a message with severity LOG_EMERG, ignoring the severity
164 // passed to New. 179 // passed to New.
165 func (w *Writer) Emerg(m string) (err error) { 180 func (w *Writer) Emerg(m string) (err error) {
166 » _, err = w.writeString(LOG_EMERG, m) 181 » _, err = w.writeAndRetry(LOG_EMERG, m)
167 return err 182 return err
168 } 183 }
169 184
170 // Alert logs a message with severity LOG_ALERT, ignoring the severity 185 // Alert logs a message with severity LOG_ALERT, ignoring the severity
171 // passed to New. 186 // passed to New.
172 func (w *Writer) Alert(m string) (err error) { 187 func (w *Writer) Alert(m string) (err error) {
173 » _, err = w.writeString(LOG_ALERT, m) 188 » _, err = w.writeAndRetry(LOG_ALERT, m)
174 return err 189 return err
175 } 190 }
176 191
177 // Crit logs a message with severity LOG_CRIT, ignoring the severity 192 // Crit logs a message with severity LOG_CRIT, ignoring the severity
178 // passed to New. 193 // passed to New.
179 func (w *Writer) Crit(m string) (err error) { 194 func (w *Writer) Crit(m string) (err error) {
180 » _, err = w.writeString(LOG_CRIT, m) 195 » _, err = w.writeAndRetry(LOG_CRIT, m)
181 return err 196 return err
182 } 197 }
183 198
184 // Err logs a message with severity LOG_ERR, ignoring the severity 199 // Err logs a message with severity LOG_ERR, ignoring the severity
185 // passed to New. 200 // passed to New.
186 func (w *Writer) Err(m string) (err error) { 201 func (w *Writer) Err(m string) (err error) {
187 » _, err = w.writeString(LOG_ERR, m) 202 » _, err = w.writeAndRetry(LOG_ERR, m)
188 return err 203 return err
189 } 204 }
190 205
191 // Wanring logs a message with severity LOG_WARNING, ignoring the 206 // Wanring logs a message with severity LOG_WARNING, ignoring the
192 // severity passed to New. 207 // severity passed to New.
193 func (w *Writer) Warning(m string) (err error) { 208 func (w *Writer) Warning(m string) (err error) {
194 » _, err = w.writeString(LOG_WARNING, m) 209 » _, err = w.writeAndRetry(LOG_WARNING, m)
195 return err 210 return err
196 } 211 }
197 212
198 // Notice logs a message with severity LOG_NOTICE, ignoring the 213 // Notice logs a message with severity LOG_NOTICE, ignoring the
199 // severity passed to New. 214 // severity passed to New.
200 func (w *Writer) Notice(m string) (err error) { 215 func (w *Writer) Notice(m string) (err error) {
201 » _, err = w.writeString(LOG_NOTICE, m) 216 » _, err = w.writeAndRetry(LOG_NOTICE, m)
202 return err 217 return err
203 } 218 }
204 219
205 // Info logs a message with severity LOG_INFO, ignoring the severity 220 // Info logs a message with severity LOG_INFO, ignoring the severity
206 // passed to New. 221 // passed to New.
207 func (w *Writer) Info(m string) (err error) { 222 func (w *Writer) Info(m string) (err error) {
208 » _, err = w.writeString(LOG_INFO, m) 223 » _, err = w.writeAndRetry(LOG_INFO, m)
209 return err 224 return err
210 } 225 }
211 226
212 // Debug logs a message with severity LOG_DEBUG, ignoring the severity 227 // Debug logs a message with severity LOG_DEBUG, ignoring the severity
213 // passed to New. 228 // passed to New.
214 func (w *Writer) Debug(m string) (err error) { 229 func (w *Writer) Debug(m string) (err error) {
215 » _, err = w.writeString(LOG_DEBUG, m) 230 » _, err = w.writeAndRetry(LOG_DEBUG, m)
216 » return err 231 » return err
217 } 232 }
218 233
219 func (w *Writer) writeString(p Priority, s string) (int, error) { 234 func (w *Writer) writeAndRetry(p Priority, s string) (int, error) {
220 » if w.conn == nil { 235 » pr := (w.priority & facilityMask) | (p & severityMask)
221 » » err := w.reconnect() 236
222 » » if err != nil { 237 » w.mu.Lock()
223 » » » return 0, err 238 » defer w.mu.Unlock()
239
240 » if w.conn != nil {
241 » » if n, err := w.write(pr, s); err == nil {
242 » » » return n, err
224 } 243 }
225 } 244 }
226 » n, err := w.conn.writeString((w.priority&facilityMask)|(p&severityMask), 245 » if err := w.connect(); err != nil {
227 » » w.hostname, w.tag, s)
228 » if err == nil {
229 » » // normal exit
230 » » return n, err
231 » }
232
233 » // error recovery: maybe try to reopen connection
234
235 » if !shouldRetry(err) {
236 » » return n, err
237 » }
238
239 » err = w.reconnect()
240 » if err != nil {
241 return 0, err 246 return 0, err
242 } 247 }
243 » return w.conn.writeString((w.priority&facilityMask)|(p&severityMask), 248 » return w.write(pr, s)
244 » » w.hostname, w.tag, s) 249 }
245 } 250
246 251 // write generates and writes a syslog formatted string. The
247 // writeString: generates and writes a syslog formatted string. The 252 // format is as follows: <PRI>TIMESTAMP HOSTNAME TAG[PID]: MSG
248 // format is as follows: <PRI>1 TIMESTAMP HOSTNAME TAG[PID]: MSG 253 func (w *Writer) write(p Priority, msg string) (int, error) {
249 func (n netConn) writeString(p Priority, hostname, tag, msg string) (int, error) { 254 » // ensure it ends in a \n
250 nl := "" 255 nl := ""
251 » if len(msg) == 0 || msg[len(msg)-1] != '\n' { 256 » if !strings.HasSuffix(msg, "\n") {
252 nl = "\n" 257 nl = "\n"
253 } 258 }
259
254 timestamp := time.Now().Format(time.RFC3339) 260 timestamp := time.Now().Format(time.RFC3339)
255 » if _, err := fmt.Fprintf(n.conn, "<%d>1 %s %s %s[%d]: %s%s", p, timestam p, hostname, 261 » fmt.Fprintf(w.conn, "<%d>%s %s %s[%d]: %s%s",
256 » » tag, os.Getpid(), msg, nl); err != nil { 262 » » p, timestamp, w.hostname,
257 » » return 0, err 263 » » w.tag, os.Getpid(), msg, nl)
258 » }
259 return len(msg), nil 264 return len(msg), nil
260 }
261
262 func (n netConn) close() error {
263 return n.conn.Close()
264 } 265 }
265 266
266 // NewLogger creates a log.Logger whose output is written to 267 // NewLogger creates a log.Logger whose output is written to
267 // the system log service with the specified priority. The logFlag 268 // the system log service with the specified priority. The logFlag
268 // argument is the flag set passed through to log.New to create 269 // argument is the flag set passed through to log.New to create
269 // the Logger. 270 // the Logger.
270 func NewLogger(p Priority, logFlag int) (*log.Logger, error) { 271 func NewLogger(p Priority, logFlag int) (*log.Logger, error) {
271 s, err := New(p, "") 272 s, err := New(p, "")
272 if err != nil { 273 if err != nil {
273 return nil, err 274 return nil, err
274 } 275 }
275 return log.New(s, "", logFlag), nil 276 return log.New(s, "", logFlag), nil
276 } 277 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b