|
|
@@ -0,0 +1,126 @@
|
|
|
+// Copyright (C) 2015 The Syncthing Authors.
|
|
|
+//
|
|
|
+// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
+// You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
+
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+
|
|
|
+ "github.com/syncthing/syncthing/internal/events"
|
|
|
+)
|
|
|
+
|
|
|
+// The verbose logging service subscribes to events and prints these in
|
|
|
+// verbose format to the console using INFO level.
|
|
|
+type verboseSvc struct {
|
|
|
+ stop chan struct{} // signals time to stop
|
|
|
+ started chan struct{} // signals startup complete
|
|
|
+}
|
|
|
+
|
|
|
+func newVerboseSvc() *verboseSvc {
|
|
|
+ return &verboseSvc{
|
|
|
+ stop: make(chan struct{}),
|
|
|
+ started: make(chan struct{}),
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Serve runs the verbose logging service.
|
|
|
+func (s *verboseSvc) Serve() {
|
|
|
+ sub := events.Default.Subscribe(events.AllEvents)
|
|
|
+ defer events.Default.Unsubscribe(sub)
|
|
|
+
|
|
|
+ // We're ready to start processing events.
|
|
|
+ close(s.started)
|
|
|
+
|
|
|
+ for {
|
|
|
+ select {
|
|
|
+ case ev := <-sub.C():
|
|
|
+ formatted := s.formatEvent(ev)
|
|
|
+ if formatted != "" {
|
|
|
+ l.Verboseln(formatted)
|
|
|
+ }
|
|
|
+ case <-s.stop:
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Stop stops the verbose logging service.
|
|
|
+func (s *verboseSvc) Stop() {
|
|
|
+ close(s.stop)
|
|
|
+}
|
|
|
+
|
|
|
+// WaitForStart returns once the verbose logging service is ready to receive
|
|
|
+// events, or immediately if it's already running.
|
|
|
+func (s *verboseSvc) WaitForStart() {
|
|
|
+ <-s.started
|
|
|
+}
|
|
|
+
|
|
|
+func (s *verboseSvc) formatEvent(ev events.Event) string {
|
|
|
+ switch ev.Type {
|
|
|
+ case events.Ping, events.DownloadProgress:
|
|
|
+ // Skip
|
|
|
+ return ""
|
|
|
+
|
|
|
+ case events.Starting:
|
|
|
+ return fmt.Sprintf("Starting up (%s)", ev.Data.(map[string]string)["home"])
|
|
|
+ case events.StartupComplete:
|
|
|
+ return "Startup complete"
|
|
|
+
|
|
|
+ case events.DeviceDiscovered:
|
|
|
+ data := ev.Data.(map[string]interface{})
|
|
|
+ return fmt.Sprintf("Discovered device %v at %v", data["device"], data["addrs"])
|
|
|
+ case events.DeviceConnected:
|
|
|
+ data := ev.Data.(map[string]string)
|
|
|
+ return fmt.Sprintf("Connected to device %v at %v", data["id"], data["addr"])
|
|
|
+ case events.DeviceDisconnected:
|
|
|
+ data := ev.Data.(map[string]string)
|
|
|
+ return fmt.Sprintf("Disconnected from device %v", data["id"])
|
|
|
+
|
|
|
+ case events.StateChanged:
|
|
|
+ data := ev.Data.(map[string]interface{})
|
|
|
+ return fmt.Sprintf("Folder %q is now %v", data["folder"], data["to"])
|
|
|
+
|
|
|
+ case events.RemoteIndexUpdated:
|
|
|
+ data := ev.Data.(map[string]interface{})
|
|
|
+ return fmt.Sprintf("Device %v sent an index update for %q with %d items", data["device"], data["folder"], data["items"])
|
|
|
+ case events.LocalIndexUpdated:
|
|
|
+ data := ev.Data.(map[string]interface{})
|
|
|
+ return fmt.Sprintf("Updated index for folder %q with %v items", data["folder"], data["items"])
|
|
|
+
|
|
|
+ case events.DeviceRejected:
|
|
|
+ data := ev.Data.(map[string]interface{})
|
|
|
+ return fmt.Sprintf("Rejected connection from device %v at %v", data["device"], data["address"])
|
|
|
+ case events.FolderRejected:
|
|
|
+ data := ev.Data.(map[string]string)
|
|
|
+ return fmt.Sprintf("Rejected unshared folder %q from device %v", data["folder"], data["device"])
|
|
|
+
|
|
|
+ case events.ItemStarted:
|
|
|
+ data := ev.Data.(map[string]interface{})
|
|
|
+ return fmt.Sprintf("Started syncing %q / %q (%v %v)", data["folder"], data["item"], data["action"], data["type"])
|
|
|
+ case events.ItemFinished:
|
|
|
+ data := ev.Data.(map[string]interface{})
|
|
|
+ if err := data["err"]; err != nil {
|
|
|
+ return fmt.Sprintf("Finished syncing %q / %q (%v %v): %v", data["folder"], data["item"], data["action"], data["type"], err)
|
|
|
+ }
|
|
|
+ return fmt.Sprintf("Finished syncing %q / %q (%v %v): Success", data["folder"], data["item"], data["action"], data["type"])
|
|
|
+
|
|
|
+ case events.ConfigSaved:
|
|
|
+ return "Configuration was saved"
|
|
|
+
|
|
|
+ case events.FolderCompletion:
|
|
|
+ data := ev.Data.(map[string]interface{})
|
|
|
+ return fmt.Sprintf("Completion for folder %q on device %v is %v%%", data["folder"], data["device"], data["completion"])
|
|
|
+ case events.FolderSummary:
|
|
|
+ data := ev.Data.(map[string]interface{})
|
|
|
+ sum := data["summary"].(map[string]interface{})
|
|
|
+ delete(sum, "invalid")
|
|
|
+ delete(sum, "ignorePatterns")
|
|
|
+ delete(sum, "stateChanged")
|
|
|
+ return fmt.Sprintf("Summary for folder %q is %v", data["folder"], data["summary"])
|
|
|
+ }
|
|
|
+
|
|
|
+ return fmt.Sprintf("%s %#v", ev.Type, ev)
|
|
|
+}
|