syslog.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // +build linux
  2. package syslog
  3. import (
  4. "errors"
  5. "fmt"
  6. "log/syslog"
  7. "net"
  8. "net/url"
  9. "os"
  10. "path"
  11. "strconv"
  12. "strings"
  13. "github.com/Sirupsen/logrus"
  14. "github.com/docker/docker/daemon/logger"
  15. "github.com/docker/docker/pkg/urlutil"
  16. )
  17. const name = "syslog"
  18. var facilities = map[string]syslog.Priority{
  19. "kern": syslog.LOG_KERN,
  20. "user": syslog.LOG_USER,
  21. "mail": syslog.LOG_MAIL,
  22. "daemon": syslog.LOG_DAEMON,
  23. "auth": syslog.LOG_AUTH,
  24. "syslog": syslog.LOG_SYSLOG,
  25. "lpr": syslog.LOG_LPR,
  26. "news": syslog.LOG_NEWS,
  27. "uucp": syslog.LOG_UUCP,
  28. "cron": syslog.LOG_CRON,
  29. "authpriv": syslog.LOG_AUTHPRIV,
  30. "ftp": syslog.LOG_FTP,
  31. "local0": syslog.LOG_LOCAL0,
  32. "local1": syslog.LOG_LOCAL1,
  33. "local2": syslog.LOG_LOCAL2,
  34. "local3": syslog.LOG_LOCAL3,
  35. "local4": syslog.LOG_LOCAL4,
  36. "local5": syslog.LOG_LOCAL5,
  37. "local6": syslog.LOG_LOCAL6,
  38. "local7": syslog.LOG_LOCAL7,
  39. }
  40. type Syslog struct {
  41. writer *syslog.Writer
  42. }
  43. func init() {
  44. if err := logger.RegisterLogDriver(name, New); err != nil {
  45. logrus.Fatal(err)
  46. }
  47. if err := logger.RegisterLogOptValidator(name, ValidateLogOpt); err != nil {
  48. logrus.Fatal(err)
  49. }
  50. }
  51. func New(ctx logger.Context) (logger.Logger, error) {
  52. tag := ctx.Config["syslog-tag"]
  53. if tag == "" {
  54. tag = ctx.ContainerID[:12]
  55. }
  56. proto, address, err := parseAddress(ctx.Config["syslog-address"])
  57. if err != nil {
  58. return nil, err
  59. }
  60. facility, err := parseFacility(ctx.Config["syslog-facility"])
  61. if err != nil {
  62. return nil, err
  63. }
  64. log, err := syslog.Dial(
  65. proto,
  66. address,
  67. facility,
  68. path.Base(os.Args[0])+"/"+tag,
  69. )
  70. if err != nil {
  71. return nil, err
  72. }
  73. return &Syslog{
  74. writer: log,
  75. }, nil
  76. }
  77. func (s *Syslog) Log(msg *logger.Message) error {
  78. if msg.Source == "stderr" {
  79. return s.writer.Err(string(msg.Line))
  80. }
  81. return s.writer.Info(string(msg.Line))
  82. }
  83. func (s *Syslog) Close() error {
  84. return s.writer.Close()
  85. }
  86. func (s *Syslog) Name() string {
  87. return name
  88. }
  89. func parseAddress(address string) (string, string, error) {
  90. if urlutil.IsTransportURL(address) {
  91. url, err := url.Parse(address)
  92. if err != nil {
  93. return "", "", err
  94. }
  95. // unix socket validation
  96. if url.Scheme == "unix" {
  97. if _, err := os.Stat(url.Path); err != nil {
  98. return "", "", err
  99. }
  100. return url.Scheme, url.Path, nil
  101. }
  102. // here we process tcp|udp
  103. host := url.Host
  104. if _, _, err := net.SplitHostPort(host); err != nil {
  105. if !strings.Contains(err.Error(), "missing port in address") {
  106. return "", "", err
  107. }
  108. host = host + ":514"
  109. }
  110. return url.Scheme, host, nil
  111. }
  112. return "", "", nil
  113. }
  114. func ValidateLogOpt(cfg map[string]string) error {
  115. for key := range cfg {
  116. switch key {
  117. case "syslog-address":
  118. case "syslog-tag":
  119. case "syslog-facility":
  120. default:
  121. return fmt.Errorf("unknown log opt '%s' for syslog log driver", key)
  122. }
  123. }
  124. return nil
  125. }
  126. func parseFacility(facility string) (syslog.Priority, error) {
  127. if facility == "" {
  128. return syslog.LOG_DAEMON, nil
  129. }
  130. if syslogFacility, valid := facilities[facility]; valid {
  131. return syslogFacility, nil
  132. }
  133. fInt, err := strconv.Atoi(facility)
  134. if err == nil && 0 <= fInt && fInt <= 23 {
  135. return syslog.Priority(fInt << 3), nil
  136. }
  137. return syslog.Priority(0), errors.New("invalid syslog facility")
  138. }