writer.go 4.9 KB

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