log.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. package log
  2. import (
  3. "fmt"
  4. "io"
  5. "log/syslog"
  6. "os"
  7. "path/filepath"
  8. "strings"
  9. "github.com/rancher/os/config/cmdline"
  10. "github.com/Sirupsen/logrus"
  11. lsyslog "github.com/Sirupsen/logrus/hooks/syslog"
  12. )
  13. var logFile *os.File
  14. var userHook *ShowuserlogHook
  15. var defaultLogLevel logrus.Level
  16. var debugThisLogger = false
  17. type Fields logrus.Fields
  18. type Level logrus.Level
  19. type Logger logrus.Logger
  20. const (
  21. // PanicLevel level, highest level of severity. Logs and then calls panic with the
  22. // message passed to Debug, Info, ...
  23. PanicLevel Level = iota
  24. // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
  25. // logging level is set to Panic.
  26. FatalLevel
  27. // ErrorLevel level. Logs. Used for errors that should definitely be noted.
  28. // Commonly used for hooks to send errors to an error tracking service.
  29. ErrorLevel
  30. // WarnLevel level. Non-critical entries that deserve eyes.
  31. WarnLevel
  32. // InfoLevel level. General operational entries about what's going on inside the
  33. // application.
  34. InfoLevel
  35. // DebugLevel level. Usually only enabled when debugging. Very verbose logging.
  36. DebugLevel
  37. )
  38. func SetOutput(out io.Writer) {
  39. logrus.SetOutput(out)
  40. }
  41. func SetDefaultLevel(level Level) {
  42. defaultLogLevel = logrus.Level(level)
  43. }
  44. func SetLevel(level Level) {
  45. if userHook != nil {
  46. userHook.Level = logrus.Level(level)
  47. } else {
  48. logrus.SetLevel(logrus.Level(level))
  49. }
  50. }
  51. func GetLevel() Level {
  52. if userHook != nil {
  53. return Level(userHook.Level)
  54. }
  55. return Level(logrus.GetLevel())
  56. }
  57. func Debugf(format string, args ...interface{}) {
  58. logrus.Debugf(format, args...)
  59. }
  60. func Infof(format string, args ...interface{}) {
  61. logrus.Infof(format, args...)
  62. }
  63. func Printf(format string, args ...interface{}) {
  64. logrus.Printf(format, args...)
  65. }
  66. func Warnf(format string, args ...interface{}) {
  67. logrus.Warnf(format, args...)
  68. }
  69. func Warningf(format string, args ...interface{}) {
  70. logrus.Warningf(format, args...)
  71. }
  72. func Errorf(format string, args ...interface{}) {
  73. logrus.Errorf(format, args...)
  74. }
  75. func Fatalf(format string, args ...interface{}) {
  76. logrus.Fatalf(format, args...)
  77. }
  78. func Panicf(format string, args ...interface{}) {
  79. logrus.Panicf(format, args...)
  80. }
  81. func Debug(args ...interface{}) {
  82. logrus.Debug(args...)
  83. }
  84. func Info(args ...interface{}) {
  85. logrus.Info(args...)
  86. }
  87. func Print(args ...interface{}) {
  88. logrus.Print(args...)
  89. }
  90. func Warn(args ...interface{}) {
  91. logrus.Warn(args...)
  92. }
  93. func Warning(args ...interface{}) {
  94. logrus.Warning(args...)
  95. }
  96. func Error(args ...interface{}) {
  97. logrus.Error(args...)
  98. }
  99. func Fatal(args ...interface{}) {
  100. logrus.Fatal(args...)
  101. }
  102. func Panic(args ...interface{}) {
  103. logrus.Panic(args...)
  104. }
  105. func WithField(key string, value interface{}) *logrus.Entry {
  106. return logrus.WithField(key, value)
  107. }
  108. func WithFields(fields Fields) *logrus.Entry {
  109. return logrus.WithFields(logrus.Fields(fields))
  110. }
  111. // InitLogger sets up Logging to log to /dev/kmsg and to Syslog
  112. func InitLogger() {
  113. if logTheseApps() {
  114. innerInit(false)
  115. FsReady()
  116. AddRSyslogHook()
  117. pwd, err := os.Getwd()
  118. if err != nil {
  119. logrus.Error(err)
  120. }
  121. logrus.Debugf("START: %v in %s", os.Args, pwd)
  122. }
  123. }
  124. func logTheseApps() bool {
  125. // TODO: mmm, not very functional.
  126. if filepath.Base(os.Args[0]) == "ros" ||
  127. // filepath.Base(os.Args[0]) == "system-docker" ||
  128. filepath.Base(os.Args[0]) == "host_ros" {
  129. return false
  130. }
  131. return true
  132. }
  133. // InitDeferedLogger stores the log messages until FsReady() is called
  134. // TODO: actually store them :)
  135. // TODO: need to work out how to pass entries from a binary run before we switchfs back to init and have it store and write it later
  136. func InitDeferedLogger() {
  137. if logTheseApps() {
  138. innerInit(true)
  139. //logrus.SetOutput(ioutil.Discard)
  140. // write to dmesg until we can write to file. (maybe we can do this if rancher.debug=true?)
  141. f, err := os.OpenFile("/dev/kmsg", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
  142. if err == nil {
  143. logFile = f
  144. logrus.SetOutput(logFile)
  145. }
  146. pwd, err := os.Getwd()
  147. if err != nil {
  148. logrus.Error(err)
  149. }
  150. logrus.Debugf("START: %v in %s", os.Args, pwd)
  151. }
  152. }
  153. func innerInit(deferedHook bool) {
  154. if userHook != nil {
  155. return // we've already initialised it
  156. }
  157. // All logs go through the Hooks, and they choose what to do with them.
  158. logrus.StandardLogger().Level = logrus.DebugLevel
  159. if logTheseApps() {
  160. AddUserHook(deferedHook)
  161. }
  162. }
  163. // AddRSyslogHook only needs to be called separately when using the InitDeferedLogger
  164. // init.Main can't read /proc/cmdline at start.
  165. // and then fails due to the network not being up
  166. // TODO: create a "defered SyslogHook that always gets initialised, but if it fails to connect, stores the logs
  167. // and retries connecting every time its triggered....
  168. func AddRSyslogHook() {
  169. val := cmdline.GetCmdline("netconsole")
  170. netconsole := val.(string)
  171. if netconsole != "" {
  172. // "loglevel=8 [email protected]/,[email protected]/"
  173. // 192.168.33.148:514
  174. n := strings.Split(netconsole, ",")
  175. if len(n) == 2 {
  176. d := strings.Split(n[1], "@")
  177. if len(d) == 2 {
  178. netconsoleDestination := fmt.Sprintf("%s:%s", strings.TrimRight(d[1], "/"), d[0])
  179. hook, err := lsyslog.NewSyslogHook("udp", netconsoleDestination, syslog.LOG_DEBUG, "")
  180. if err == nil {
  181. logrus.StandardLogger().Hooks.Add(hook)
  182. Infof("Sending RancherOS Logs to: %s", netconsoleDestination)
  183. } else {
  184. Errorf("Error creating SyslogHook: %s", err)
  185. }
  186. }
  187. }
  188. }
  189. }
  190. func FsReady() {
  191. filename := "/var/log/boot/" + filepath.Base(os.Args[0]) + ".log"
  192. if err := os.MkdirAll(filepath.Dir(filename), os.ModeDir|0755); debugThisLogger && err != nil {
  193. logrus.Errorf("FsReady mkdir(%s): %s", filename, err)
  194. }
  195. f, err := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
  196. if err != nil {
  197. if debugThisLogger {
  198. logrus.Errorf("FsReady opening %s: %s", filename, err)
  199. }
  200. } else {
  201. if debugThisLogger {
  202. logrus.Infof("Setting log output for %s to: %s", os.Args[0], filename)
  203. }
  204. logFile = f
  205. logrus.SetOutput(logFile)
  206. }
  207. }
  208. // AddUserHook is used to filter what log messages are written to the screen
  209. func AddUserHook(deferedHook bool) error {
  210. if userHook != nil {
  211. return nil
  212. }
  213. printLogLevel := logrus.InfoLevel
  214. uh, err := NewShowuserlogHook(printLogLevel, filepath.Base(os.Args[0]))
  215. if err != nil {
  216. logrus.Errorf("error creating userHook(%s): %s", os.Args[0], err)
  217. return err
  218. }
  219. userHook = uh
  220. logrus.StandardLogger().Hooks.Add(uh)
  221. if debugThisLogger {
  222. if deferedHook {
  223. logrus.Debugf("------------info Starting defered User Hook (%s)", os.Args[0])
  224. } else {
  225. logrus.Debugf("------------info Starting User Hook (%s)", os.Args[0])
  226. }
  227. }
  228. return nil
  229. }