writer.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. package srslog
  2. import (
  3. "crypto/tls"
  4. "strings"
  5. "sync"
  6. )
  7. // A Writer is a connection to a syslog server.
  8. type Writer struct {
  9. priority Priority
  10. tag string
  11. hostname string
  12. network string
  13. raddr string
  14. tlsConfig *tls.Config
  15. framer Framer
  16. formatter Formatter
  17. //non-nil if custom dialer set, used in getDialer
  18. customDial DialFunc
  19. mu sync.RWMutex // guards conn
  20. conn serverConn
  21. }
  22. // getConn provides access to the internal conn, protected by a mutex. The
  23. // conn is threadsafe, so it can be used while unlocked, but we want to avoid
  24. // race conditions on grabbing a reference to it.
  25. func (w *Writer) getConn() serverConn {
  26. w.mu.RLock()
  27. conn := w.conn
  28. w.mu.RUnlock()
  29. return conn
  30. }
  31. // setConn updates the internal conn, protected by a mutex.
  32. func (w *Writer) setConn(c serverConn) {
  33. w.mu.Lock()
  34. w.conn = c
  35. w.mu.Unlock()
  36. }
  37. // connect makes a connection to the syslog server.
  38. func (w *Writer) connect() (serverConn, error) {
  39. conn := w.getConn()
  40. if conn != nil {
  41. // ignore err from close, it makes sense to continue anyway
  42. conn.close()
  43. w.setConn(nil)
  44. }
  45. var hostname string
  46. var err error
  47. dialer := w.getDialer()
  48. conn, hostname, err = dialer.Call()
  49. if err == nil {
  50. w.setConn(conn)
  51. w.hostname = hostname
  52. return conn, nil
  53. } else {
  54. return nil, err
  55. }
  56. }
  57. // SetFormatter changes the formatter function for subsequent messages.
  58. func (w *Writer) SetFormatter(f Formatter) {
  59. w.formatter = f
  60. }
  61. // SetFramer changes the framer function for subsequent messages.
  62. func (w *Writer) SetFramer(f Framer) {
  63. w.framer = f
  64. }
  65. // SetHostname changes the hostname for syslog messages if needed.
  66. func (w *Writer) SetHostname(hostname string) {
  67. w.hostname = hostname
  68. }
  69. // Write sends a log message to the syslog daemon using the default priority
  70. // passed into `srslog.New` or the `srslog.Dial*` functions.
  71. func (w *Writer) Write(b []byte) (int, error) {
  72. return w.writeAndRetry(w.priority, string(b))
  73. }
  74. // WriteWithPriority sends a log message with a custom priority.
  75. func (w *Writer) WriteWithPriority(p Priority, b []byte) (int, error) {
  76. return w.writeAndRetryWithPriority(p, string(b))
  77. }
  78. // Close closes a connection to the syslog daemon.
  79. func (w *Writer) Close() error {
  80. conn := w.getConn()
  81. if conn != nil {
  82. err := conn.close()
  83. w.setConn(nil)
  84. return err
  85. }
  86. return nil
  87. }
  88. // Emerg logs a message with severity LOG_EMERG; this overrides the default
  89. // priority passed to `srslog.New` and the `srslog.Dial*` functions.
  90. func (w *Writer) Emerg(m string) (err error) {
  91. _, err = w.writeAndRetry(LOG_EMERG, m)
  92. return err
  93. }
  94. // Alert logs a message with severity LOG_ALERT; this overrides the default
  95. // priority passed to `srslog.New` and the `srslog.Dial*` functions.
  96. func (w *Writer) Alert(m string) (err error) {
  97. _, err = w.writeAndRetry(LOG_ALERT, m)
  98. return err
  99. }
  100. // Crit logs a message with severity LOG_CRIT; this overrides the default
  101. // priority passed to `srslog.New` and the `srslog.Dial*` functions.
  102. func (w *Writer) Crit(m string) (err error) {
  103. _, err = w.writeAndRetry(LOG_CRIT, m)
  104. return err
  105. }
  106. // Err logs a message with severity LOG_ERR; this overrides the default
  107. // priority passed to `srslog.New` and the `srslog.Dial*` functions.
  108. func (w *Writer) Err(m string) (err error) {
  109. _, err = w.writeAndRetry(LOG_ERR, m)
  110. return err
  111. }
  112. // Warning logs a message with severity LOG_WARNING; this overrides the default
  113. // priority passed to `srslog.New` and the `srslog.Dial*` functions.
  114. func (w *Writer) Warning(m string) (err error) {
  115. _, err = w.writeAndRetry(LOG_WARNING, m)
  116. return err
  117. }
  118. // Notice logs a message with severity LOG_NOTICE; this overrides the default
  119. // priority passed to `srslog.New` and the `srslog.Dial*` functions.
  120. func (w *Writer) Notice(m string) (err error) {
  121. _, err = w.writeAndRetry(LOG_NOTICE, m)
  122. return err
  123. }
  124. // Info logs a message with severity LOG_INFO; this overrides the default
  125. // priority passed to `srslog.New` and the `srslog.Dial*` functions.
  126. func (w *Writer) Info(m string) (err error) {
  127. _, err = w.writeAndRetry(LOG_INFO, m)
  128. return err
  129. }
  130. // Debug logs a message with severity LOG_DEBUG; this overrides the default
  131. // priority passed to `srslog.New` and the `srslog.Dial*` functions.
  132. func (w *Writer) Debug(m string) (err error) {
  133. _, err = w.writeAndRetry(LOG_DEBUG, m)
  134. return err
  135. }
  136. // writeAndRetry takes a severity and the string to write. Any facility passed to
  137. // it as part of the severity Priority will be ignored.
  138. func (w *Writer) writeAndRetry(severity Priority, s string) (int, error) {
  139. pr := (w.priority & facilityMask) | (severity & severityMask)
  140. return w.writeAndRetryWithPriority(pr, s)
  141. }
  142. // writeAndRetryWithPriority differs from writeAndRetry in that it allows setting
  143. // of both the facility and the severity.
  144. func (w *Writer) writeAndRetryWithPriority(p Priority, s string) (int, error) {
  145. conn := w.getConn()
  146. if conn != nil {
  147. if n, err := w.write(conn, p, s); err == nil {
  148. return n, err
  149. }
  150. }
  151. var err error
  152. if conn, err = w.connect(); err != nil {
  153. return 0, err
  154. }
  155. return w.write(conn, p, s)
  156. }
  157. // write generates and writes a syslog formatted string. It formats the
  158. // message based on the current Formatter and Framer.
  159. func (w *Writer) write(conn serverConn, p Priority, msg string) (int, error) {
  160. // ensure it ends in a \n
  161. if !strings.HasSuffix(msg, "\n") {
  162. msg += "\n"
  163. }
  164. err := conn.writeString(w.framer, w.formatter, p, w.hostname, w.tag, msg)
  165. if err != nil {
  166. return 0, err
  167. }
  168. // Note: return the length of the input, not the number of
  169. // bytes printed by Fprintf, because this must behave like
  170. // an io.Writer.
  171. return len(msg), nil
  172. }