verboseservice.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // Copyright (C) 2015 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package syncthing
  7. import (
  8. "fmt"
  9. "github.com/thejerf/suture"
  10. "github.com/syncthing/syncthing/lib/events"
  11. "github.com/syncthing/syncthing/lib/util"
  12. )
  13. // The verbose logging service subscribes to events and prints these in
  14. // verbose format to the console using INFO level.
  15. type verboseService struct {
  16. suture.Service
  17. sub *events.Subscription
  18. }
  19. func newVerboseService() *verboseService {
  20. s := &verboseService{
  21. sub: events.Default.Subscribe(events.AllEvents),
  22. }
  23. s.Service = util.AsService(s.serve)
  24. return s
  25. }
  26. // serve runs the verbose logging service.
  27. func (s *verboseService) serve(stop chan struct{}) {
  28. for {
  29. select {
  30. case ev := <-s.sub.C():
  31. formatted := s.formatEvent(ev)
  32. if formatted != "" {
  33. l.Verboseln(formatted)
  34. }
  35. case <-stop:
  36. return
  37. }
  38. }
  39. }
  40. // Stop stops the verbose logging service.
  41. func (s *verboseService) Stop() {
  42. s.Service.Stop()
  43. events.Default.Unsubscribe(s.sub)
  44. }
  45. func (s *verboseService) formatEvent(ev events.Event) string {
  46. switch ev.Type {
  47. case events.DownloadProgress, events.LocalIndexUpdated:
  48. // Skip
  49. return ""
  50. case events.Starting:
  51. return fmt.Sprintf("Starting up (%s)", ev.Data.(map[string]string)["home"])
  52. case events.StartupComplete:
  53. return "Startup complete"
  54. case events.DeviceDiscovered:
  55. data := ev.Data.(map[string]interface{})
  56. return fmt.Sprintf("Discovered device %v at %v", data["device"], data["addrs"])
  57. case events.DeviceConnected:
  58. data := ev.Data.(map[string]string)
  59. return fmt.Sprintf("Connected to device %v at %v (type %s)", data["id"], data["addr"], data["type"])
  60. case events.DeviceDisconnected:
  61. data := ev.Data.(map[string]string)
  62. return fmt.Sprintf("Disconnected from device %v", data["id"])
  63. case events.StateChanged:
  64. data := ev.Data.(map[string]interface{})
  65. return fmt.Sprintf("Folder %q is now %v", data["folder"], data["to"])
  66. case events.LocalChangeDetected:
  67. data := ev.Data.(map[string]string)
  68. return fmt.Sprintf("Local change detected in folder %q: %s %s %s", data["folder"], data["action"], data["type"], data["path"])
  69. case events.RemoteChangeDetected:
  70. data := ev.Data.(map[string]string)
  71. return fmt.Sprintf("Remote change detected in folder %q: %s %s %s", data["folder"], data["action"], data["type"], data["path"])
  72. case events.RemoteIndexUpdated:
  73. data := ev.Data.(map[string]interface{})
  74. return fmt.Sprintf("Device %v sent an index update for %q with %d items", data["device"], data["folder"], data["items"])
  75. case events.DeviceRejected:
  76. data := ev.Data.(map[string]string)
  77. return fmt.Sprintf("Rejected connection from device %v at %v", data["device"], data["address"])
  78. case events.FolderRejected:
  79. data := ev.Data.(map[string]string)
  80. return fmt.Sprintf("Rejected unshared folder %q from device %v", data["folder"], data["device"])
  81. case events.ItemStarted:
  82. data := ev.Data.(map[string]string)
  83. return fmt.Sprintf("Started syncing %q / %q (%v %v)", data["folder"], data["item"], data["action"], data["type"])
  84. case events.ItemFinished:
  85. data := ev.Data.(map[string]interface{})
  86. if err, ok := data["error"].(*string); ok && err != nil {
  87. // If the err interface{} is not nil, it is a string pointer.
  88. // Dereference it to get the actual error or Sprintf will print
  89. // the pointer value....
  90. return fmt.Sprintf("Finished syncing %q / %q (%v %v): %v", data["folder"], data["item"], data["action"], data["type"], *err)
  91. }
  92. return fmt.Sprintf("Finished syncing %q / %q (%v %v): Success", data["folder"], data["item"], data["action"], data["type"])
  93. case events.ConfigSaved:
  94. return "Configuration was saved"
  95. case events.FolderCompletion:
  96. data := ev.Data.(map[string]interface{})
  97. return fmt.Sprintf("Completion for folder %q on device %v is %v%%", data["folder"], data["device"], data["completion"])
  98. case events.FolderSummary:
  99. data := ev.Data.(map[string]interface{})
  100. sum := make(map[string]interface{})
  101. for k, v := range data["summary"].(map[string]interface{}) {
  102. if k == "invalid" || k == "ignorePatterns" || k == "stateChanged" {
  103. continue
  104. }
  105. sum[k] = v
  106. }
  107. return fmt.Sprintf("Summary for folder %q is %v", data["folder"], sum)
  108. case events.FolderScanProgress:
  109. data := ev.Data.(map[string]interface{})
  110. folder := data["folder"].(string)
  111. current := data["current"].(int64)
  112. total := data["total"].(int64)
  113. rate := data["rate"].(float64) / 1024 / 1024
  114. var pct int64
  115. if total > 0 {
  116. pct = 100 * current / total
  117. }
  118. return fmt.Sprintf("Scanning folder %q, %d%% done (%.01f MiB/s)", folder, pct, rate)
  119. case events.DevicePaused:
  120. data := ev.Data.(map[string]string)
  121. device := data["device"]
  122. return fmt.Sprintf("Device %v was paused", device)
  123. case events.DeviceResumed:
  124. data := ev.Data.(map[string]string)
  125. device := data["device"]
  126. return fmt.Sprintf("Device %v was resumed", device)
  127. case events.FolderPaused:
  128. data := ev.Data.(map[string]string)
  129. id := data["id"]
  130. label := data["label"]
  131. return fmt.Sprintf("Folder %v (%v) was paused", id, label)
  132. case events.FolderResumed:
  133. data := ev.Data.(map[string]string)
  134. id := data["id"]
  135. label := data["label"]
  136. return fmt.Sprintf("Folder %v (%v) was resumed", id, label)
  137. case events.ListenAddressesChanged:
  138. data := ev.Data.(map[string]interface{})
  139. address := data["address"]
  140. lan := data["lan"]
  141. wan := data["wan"]
  142. return fmt.Sprintf("Listen address %s resolution has changed: lan addresses: %s wan addresses: %s", address, lan, wan)
  143. case events.LoginAttempt:
  144. data := ev.Data.(map[string]interface{})
  145. username := data["username"].(string)
  146. var success string
  147. if data["success"].(bool) {
  148. success = "successful"
  149. } else {
  150. success = "failed"
  151. }
  152. return fmt.Sprintf("Login %s for username %s.", success, username)
  153. }
  154. return fmt.Sprintf("%s %#v", ev.Type, ev)
  155. }