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 and prefix.
106 func New(priority Priority
, tag
string) (*Writer
, error
) {
107 return Dial("", "", priority
, tag
)
110 // Dial establishes a connection to a log daemon by connecting to
111 // address raddr on the specified network. Each write to the returned
112 // writer sends a log message with the given facility, severity and
114 // If network is empty, Dial will connect to the local syslog server.
115 func Dial(network
, raddr
string, priority Priority
, tag
string) (*Writer
, error
) {
116 if priority
< 0 || priority
> LOG_LOCAL7|LOG_DEBUG
{
117 return nil, errors
.New("log/syslog: invalid priority")
123 hostname
, _
:= os
.Hostname()
143 // connect makes a connection to the syslog server.
144 // It must be called with w.mu held.
145 func (w
*Writer
) connect() (err error
) {
147 // ignore err from close, it makes sense to continue anyway
153 w
.conn
, err
= unixSyslog()
154 if w
.hostname
== "" {
155 w
.hostname
= "localhost"
159 c
, err
= net
.Dial(w
.network
, w
.raddr
)
161 w
.conn
= &netConn
{conn
: c
}
162 if w
.hostname
== "" {
163 w
.hostname
= c
.LocalAddr().String()
170 // Write sends a log message to the syslog daemon.
171 func (w
*Writer
) Write(b
[]byte) (int, error
) {
172 return w
.writeAndRetry(w
.priority
, string(b
))
175 // Close closes a connection to the syslog daemon.
176 func (w
*Writer
) Close() error
{
181 err
:= w
.conn
.close()
188 // Emerg logs a message with severity LOG_EMERG, ignoring the severity
190 func (w
*Writer
) Emerg(m
string) error
{
191 _
, err
:= w
.writeAndRetry(LOG_EMERG
, m
)
195 // Alert logs a message with severity LOG_ALERT, ignoring the severity
197 func (w
*Writer
) Alert(m
string) error
{
198 _
, err
:= w
.writeAndRetry(LOG_ALERT
, m
)
202 // Crit logs a message with severity LOG_CRIT, ignoring the severity
204 func (w
*Writer
) Crit(m
string) error
{
205 _
, err
:= w
.writeAndRetry(LOG_CRIT
, m
)
209 // Err logs a message with severity LOG_ERR, ignoring the severity
211 func (w
*Writer
) Err(m
string) error
{
212 _
, err
:= w
.writeAndRetry(LOG_ERR
, m
)
216 // Warning logs a message with severity LOG_WARNING, ignoring the
217 // severity passed to New.
218 func (w
*Writer
) Warning(m
string) error
{
219 _
, err
:= w
.writeAndRetry(LOG_WARNING
, m
)
223 // Notice logs a message with severity LOG_NOTICE, ignoring the
224 // severity passed to New.
225 func (w
*Writer
) Notice(m
string) error
{
226 _
, err
:= w
.writeAndRetry(LOG_NOTICE
, m
)
230 // Info logs a message with severity LOG_INFO, ignoring the severity
232 func (w
*Writer
) Info(m
string) error
{
233 _
, err
:= w
.writeAndRetry(LOG_INFO
, m
)
237 // Debug logs a message with severity LOG_DEBUG, ignoring the severity
239 func (w
*Writer
) Debug(m
string) error
{
240 _
, err
:= w
.writeAndRetry(LOG_DEBUG
, m
)
244 func (w
*Writer
) writeAndRetry(p Priority
, s
string) (int, error
) {
245 pr
:= (w
.priority
& facilityMask
) |
(p
& severityMask
)
251 if n
, err
:= w
.write(pr
, s
); err
== nil {
255 if err
:= w
.connect(); err
!= nil {
258 return w
.write(pr
, s
)
261 // write generates and writes a syslog formatted string. The
262 // format is as follows: <PRI>TIMESTAMP HOSTNAME TAG[PID]: MSG
263 func (w
*Writer
) write(p Priority
, msg
string) (int, error
) {
264 // ensure it ends in a \n
266 if !strings
.HasSuffix(msg
, "\n") {
270 err
:= w
.conn
.writeString(p
, w
.hostname
, w
.tag
, msg
, nl
)
274 // Note: return the length of the input, not the number of
275 // bytes printed by Fprintf, because this must behave like
280 func (n
*netConn
) writeString(p Priority
, hostname
, tag
, msg
, nl
string) error
{
282 // Compared to the network form below, the changes are:
283 // 1. Use time.Stamp instead of time.RFC3339.
284 // 2. Drop the hostname field from the Fprintf.
285 timestamp
:= time
.Now().Format(time
.Stamp
)
286 _
, err
:= fmt
.Fprintf(n
.conn
, "<%d>%s %s[%d]: %s%s",
288 tag
, os
.Getpid(), msg
, nl
)
291 timestamp
:= time
.Now().Format(time
.RFC3339
)
292 _
, err
:= fmt
.Fprintf(n
.conn
, "<%d>%s %s %s[%d]: %s%s",
293 p
, timestamp
, hostname
,
294 tag
, os
.Getpid(), msg
, nl
)
298 func (n
*netConn
) close() error
{
299 return n
.conn
.Close()
302 // NewLogger creates a log.Logger whose output is written to
303 // the system log service with the specified priority. The logFlag
304 // argument is the flag set passed through to log.New to create
306 func NewLogger(p Priority
, logFlag
int) (*log
.Logger
, error
) {
311 return log
.New(s
, "", logFlag
), nil