1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // +build !windows,!nacl,!plan9
20 // The Priority is a combination of the syslog facility and
21 // severity. For example, LOG_ALERT | LOG_FTP sends an alert severity
22 // message from the FTP facility. The default severity is LOG_EMERG;
23 // the default facility is LOG_KERN.
26 const severityMask
= 0x07
27 const facilityMask
= 0xf8
32 // From /usr/include/sys/syslog.h.
33 // These are the same on Linux, BSD, and OS X.
34 LOG_EMERG Priority
= iota
47 // From /usr/include/sys/syslog.h.
48 // These are the same up to LOG_FTP on Linux, BSD, and OS X.
49 LOG_KERN Priority
= iota << 3
75 // A Writer is a connection to a syslog server.
83 mu sync
.Mutex
// guards conn
87 // This interface and the separate syslog_unix.go file exist for
88 // Solaris support as implemented by gccgo. On Solaris you cannot
89 // simply open a TCP connection to the syslog daemon. The gccgo
90 // sources have a syslog_solaris.go file that implements unixSyslog to
91 // return a type that satisfies this interface and simply calls the C
92 // library syslog function.
93 type serverConn
interface {
94 writeString(p Priority
, hostname
, tag
, s
, nl
string) error
103 // New establishes a new connection to the system log daemon. Each
104 // write to the returned writer sends a log message with the given
105 // priority (a combination of the syslog facility and severity) and
106 // prefix tag. If tag is empty, the os.Args[0] is used.
107 func New(priority Priority
, tag
string) (*Writer
, error
) {
108 return Dial("", "", priority
, tag
)
111 // Dial establishes a connection to a log daemon by connecting to
112 // address raddr on the specified network. Each write to the returned
113 // writer sends a log message with the facility and severity
114 // (from priority) and tag. If tag is empty, the os.Args[0] is used.
115 // If network is empty, Dial will connect to the local syslog server.
116 // Otherwise, see the documentation for net.Dial for valid values
117 // of network and raddr.
118 func Dial(network
, raddr
string, priority Priority
, tag
string) (*Writer
, error
) {
119 if priority
< 0 || priority
> LOG_LOCAL7|LOG_DEBUG
{
120 return nil, errors
.New("log/syslog: invalid priority")
126 hostname
, _
:= os
.Hostname()
146 // connect makes a connection to the syslog server.
147 // It must be called with w.mu held.
148 func (w
*Writer
) connect() (err error
) {
150 // ignore err from close, it makes sense to continue anyway
156 w
.conn
, err
= unixSyslog()
157 if w
.hostname
== "" {
158 w
.hostname
= "localhost"
162 c
, err
= net
.Dial(w
.network
, w
.raddr
)
164 w
.conn
= &netConn
{conn
: c
}
165 if w
.hostname
== "" {
166 w
.hostname
= c
.LocalAddr().String()
173 // Write sends a log message to the syslog daemon.
174 func (w
*Writer
) Write(b
[]byte) (int, error
) {
175 return w
.writeAndRetry(w
.priority
, string(b
))
178 // Close closes a connection to the syslog daemon.
179 func (w
*Writer
) Close() error
{
184 err
:= w
.conn
.close()
191 // Emerg logs a message with severity LOG_EMERG, ignoring the severity
193 func (w
*Writer
) Emerg(m
string) error
{
194 _
, err
:= w
.writeAndRetry(LOG_EMERG
, m
)
198 // Alert logs a message with severity LOG_ALERT, ignoring the severity
200 func (w
*Writer
) Alert(m
string) error
{
201 _
, err
:= w
.writeAndRetry(LOG_ALERT
, m
)
205 // Crit logs a message with severity LOG_CRIT, ignoring the severity
207 func (w
*Writer
) Crit(m
string) error
{
208 _
, err
:= w
.writeAndRetry(LOG_CRIT
, m
)
212 // Err logs a message with severity LOG_ERR, ignoring the severity
214 func (w
*Writer
) Err(m
string) error
{
215 _
, err
:= w
.writeAndRetry(LOG_ERR
, m
)
219 // Warning logs a message with severity LOG_WARNING, ignoring the
220 // severity passed to New.
221 func (w
*Writer
) Warning(m
string) error
{
222 _
, err
:= w
.writeAndRetry(LOG_WARNING
, m
)
226 // Notice logs a message with severity LOG_NOTICE, ignoring the
227 // severity passed to New.
228 func (w
*Writer
) Notice(m
string) error
{
229 _
, err
:= w
.writeAndRetry(LOG_NOTICE
, m
)
233 // Info logs a message with severity LOG_INFO, ignoring the severity
235 func (w
*Writer
) Info(m
string) error
{
236 _
, err
:= w
.writeAndRetry(LOG_INFO
, m
)
240 // Debug logs a message with severity LOG_DEBUG, ignoring the severity
242 func (w
*Writer
) Debug(m
string) error
{
243 _
, err
:= w
.writeAndRetry(LOG_DEBUG
, m
)
247 func (w
*Writer
) writeAndRetry(p Priority
, s
string) (int, error
) {
248 pr
:= (w
.priority
& facilityMask
) |
(p
& severityMask
)
254 if n
, err
:= w
.write(pr
, s
); err
== nil {
258 if err
:= w
.connect(); err
!= nil {
261 return w
.write(pr
, s
)
264 // write generates and writes a syslog formatted string. The
265 // format is as follows: <PRI>TIMESTAMP HOSTNAME TAG[PID]: MSG
266 func (w
*Writer
) write(p Priority
, msg
string) (int, error
) {
267 // ensure it ends in a \n
269 if !strings
.HasSuffix(msg
, "\n") {
273 err
:= w
.conn
.writeString(p
, w
.hostname
, w
.tag
, msg
, nl
)
277 // Note: return the length of the input, not the number of
278 // bytes printed by Fprintf, because this must behave like
283 func (n
*netConn
) writeString(p Priority
, hostname
, tag
, msg
, nl
string) error
{
285 // Compared to the network form below, the changes are:
286 // 1. Use time.Stamp instead of time.RFC3339.
287 // 2. Drop the hostname field from the Fprintf.
288 timestamp
:= time
.Now().Format(time
.Stamp
)
289 _
, err
:= fmt
.Fprintf(n
.conn
, "<%d>%s %s[%d]: %s%s",
291 tag
, os
.Getpid(), msg
, nl
)
294 timestamp
:= time
.Now().Format(time
.RFC3339
)
295 _
, err
:= fmt
.Fprintf(n
.conn
, "<%d>%s %s %s[%d]: %s%s",
296 p
, timestamp
, hostname
,
297 tag
, os
.Getpid(), msg
, nl
)
301 func (n
*netConn
) close() error
{
302 return n
.conn
.Close()
305 // NewLogger creates a log.Logger whose output is written to the
306 // system log service with the specified priority, a combination of
307 // the syslog facility and severity. The logFlag argument is the flag
308 // set passed through to log.New to create the Logger.
309 func NewLogger(p Priority
, logFlag
int) (*log
.Logger
, error
) {
314 return log
.New(s
, "", logFlag
), nil