Repository navigation
Expand file tree
/
Copy pathsyslog.go
More file actions
114 lines (88 loc) · 2.64 KB
/
Copy pathsyslog.go
File metadata and controls
114 lines (88 loc) · 2.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package logging
import (
"net"
"sync"
"time"
)
// SyslogWriter describes connection sink for syslog.
// It connects on first write if not connected and reconnects once if a write fails.
// Safe for concurrent use.
type SyslogWriter struct {
network string
raddr string
conn net.Conn
mu sync.Mutex // protects conn and serializes writes
}
// NewSyslogWriter returns a new conn sink for syslog.
func NewSyslogWriter(network, raddr string) (s *SyslogWriter, err error) {
s = &SyslogWriter{network: network, raddr: raddr}
if err = s.connect(); err != nil {
return nil, wrapErr(err, "connect syslog socket")
}
return s, nil
}
// connect makes a connection to the syslog server.
// If syslog server already connected new connection will be created.
func (s *SyslogWriter) connect() error {
s.mu.Lock()
defer s.mu.Unlock()
s.disconnectLocked()
return s.dialLocked()
}
// dialLocked dials the syslog server. Expects s.mu held.
func (s *SyslogWriter) dialLocked() error {
conn, err := net.DialTimeout(s.network, s.raddr, syslogTimeout) //nolint:noctx // no caller context: Write has none
if err != nil {
return wrapErr(err, "connect syslog")
}
s.conn = conn
return nil
}
// disconnectLocked closes connection if any. Expects s.mu held.
func (s *SyslogWriter) disconnectLocked() {
if s.conn == nil {
return
}
_ = s.conn.Close() // ignore err from close, it makes sense to continue anyway
s.conn = nil
}
// Write writes to syslog. If connection is not ready it tries to connect first.
// If the write fails nothing was written it reconnects and tries once more.
// Returns error if write failed or connection can not be established.
func (s *SyslogWriter) Write(p []byte) (n int, err error) {
s.mu.Lock()
defer s.mu.Unlock()
if s.conn == nil {
if err = s.dialLocked(); err != nil {
return 0, err
}
}
if n, err = s.writeLocked(p); err == nil || n > 0 {
return n, err
}
// nothing written: the connection is probably broken, try fresh one
s.disconnectLocked()
if derr := s.dialLocked(); derr != nil {
return 0, derr
}
return s.writeLocked(p)
}
func (s *SyslogWriter) writeLocked(p []byte) (int, error) {
_ = s.conn.SetWriteDeadline(time.Now().Add(syslogTimeout)) // not supported by every conn, write anyway
return s.conn.Write(p)
}
// Sync implements zapcore.WriteSyncer interface.
func (s *SyslogWriter) Sync() error {
return nil
}
// Disconnect disconnects from socket. The next Write connects again.
func (s *SyslogWriter) Disconnect() {
s.mu.Lock()
defer s.mu.Unlock()
s.disconnectLocked()
}
// Close disconnects from socket. Implements io.Closer.
func (s *SyslogWriter) Close() error {
s.Disconnect()
return nil
}