Browse Source

Publish more event details

Jakob Borg 11 years ago
parent
commit
f88a7a8e6a
5 changed files with 101 additions and 46 deletions
  1. 1 1
      cmd/syncthing/gui.go
  2. 2 0
      cmd/syncthing/main.go
  3. 12 4
      discover/discover.go
  4. 9 0
      events/events.go
  5. 77 41
      model/model.go

+ 1 - 1
cmd/syncthing/gui.go

@@ -209,7 +209,7 @@ func restGetModel(m *model.Model, w http.ResponseWriter, r *http.Request) {
 
 	res["inSyncFiles"], res["inSyncBytes"] = globalFiles-needFiles, globalBytes-needBytes
 
-	res["state"] = m.State(repo)
+	res["state"], res["stateChanged"] = m.State(repo)
 	res["version"] = m.LocalVersion(repo)
 
 	w.Header().Set("Content-Type", "application/json; charset=utf-8")

+ 2 - 0
cmd/syncthing/main.go

@@ -163,6 +163,8 @@ func main() {
 
 	confDir = expandTilde(confDir)
 
+	events.Default.Log(events.Starting, map[string]string{"home": confDir})
+
 	if _, err := os.Stat(confDir); err != nil && confDir == getDefaultConfDir() {
 		// We are supposed to use the default configuration directory. It
 		// doesn't exist. In the past our default has been ~/.syncthing, so if

+ 12 - 4
discover/discover.go

@@ -15,6 +15,7 @@ import (
 	"time"
 
 	"github.com/calmh/syncthing/beacon"
+	"github.com/calmh/syncthing/events"
 	"github.com/calmh/syncthing/protocol"
 )
 
@@ -256,12 +257,12 @@ func (d *Discoverer) recvAnnouncements() {
 
 		var newNode bool
 		if bytes.Compare(pkt.This.ID, d.myID[:]) != 0 {
-			n := d.registerNode(addr, pkt.This)
-			newNode = newNode || n
+			newNode = d.registerNode(addr, pkt.This)
 			for _, node := range pkt.Extra {
 				if bytes.Compare(node.ID, d.myID[:]) != 0 {
-					n := d.registerNode(nil, node)
-					newNode = newNode || n
+					if d.registerNode(nil, node) {
+						newNode = true
+					}
 				}
 			}
 		}
@@ -302,6 +303,13 @@ func (d *Discoverer) registerNode(addr net.Addr, node Node) bool {
 	_, seen := d.registry[id]
 	d.registry[id] = addrs
 	d.registryLock.Unlock()
+
+	if !seen {
+		events.Default.Log(events.NodeDiscovered, map[string]interface{}{
+			"node":  id.String(),
+			"addrs": addrs,
+		})
+	}
 	return !seen
 }
 

+ 9 - 0
events/events.go

@@ -11,13 +11,16 @@ type EventType uint64
 
 const (
 	Ping = 1 << iota
+	Starting
 	StartupComplete
+	NodeDiscovered
 	NodeConnected
 	NodeDisconnected
 	LocalIndexUpdated
 	RemoteIndexUpdated
 	ItemStarted
 	ItemCompleted
+	StateChanged
 
 	AllEvents = ^EventType(0)
 )
@@ -26,8 +29,12 @@ func (t EventType) String() string {
 	switch t {
 	case Ping:
 		return "Ping"
+	case Starting:
+		return "Starting"
 	case StartupComplete:
 		return "StartupComplete"
+	case NodeDiscovered:
+		return "NodeDiscovered"
 	case NodeConnected:
 		return "NodeConnected"
 	case NodeDisconnected:
@@ -38,6 +45,8 @@ func (t EventType) String() string {
 		return "RemoteIndexUpdated"
 	case ItemStarted:
 		return "ItemStarted"
+	case StateChanged:
+		return "StateChanged"
 	default:
 		return "Unknown"
 	}

+ 77 - 41
model/model.go

@@ -33,6 +33,21 @@ const (
 	RepoCleaning
 )
 
+func (s repoState) String() string {
+	switch s {
+	case RepoIdle:
+		return "idle"
+	case RepoScanning:
+		return "scanning"
+	case RepoCleaning:
+		return "cleaning"
+	case RepoSyncing:
+		return "syncing"
+	default:
+		return "unknown"
+	}
+}
+
 // Somewhat arbitrary amount of bytes that we choose to let represent the size
 // of an unsynchronized directory entry or a deleted file. We need it to be
 // larger than zero so that it's visible that there is some amount of bytes to
@@ -57,8 +72,9 @@ type Model struct {
 	suppressor map[string]*suppressor                    // repo -> suppressor
 	rmut       sync.RWMutex                              // protects the above
 
-	repoState map[string]repoState // repo -> state
-	smut      sync.RWMutex
+	repoState        map[string]repoState // repo -> state
+	repoStateChanged map[string]time.Time // repo -> time when state changed
+	smut             sync.RWMutex
 
 	protoConn map[protocol.NodeID]protocol.Connection
 	rawConn   map[protocol.NodeID]io.Closer
@@ -84,22 +100,23 @@ var (
 // for file data without altering the local repository in any way.
 func NewModel(indexDir string, cfg *config.Configuration, clientName, clientVersion string, db *leveldb.DB) *Model {
 	m := &Model{
-		indexDir:      indexDir,
-		cfg:           cfg,
-		db:            db,
-		clientName:    clientName,
-		clientVersion: clientVersion,
-		repoCfgs:      make(map[string]config.RepositoryConfiguration),
-		repoFiles:     make(map[string]*files.Set),
-		repoNodes:     make(map[string][]protocol.NodeID),
-		nodeRepos:     make(map[protocol.NodeID][]string),
-		repoState:     make(map[string]repoState),
-		suppressor:    make(map[string]*suppressor),
-		protoConn:     make(map[protocol.NodeID]protocol.Connection),
-		rawConn:       make(map[protocol.NodeID]io.Closer),
-		nodeVer:       make(map[protocol.NodeID]string),
-		sentLocalVer:  make(map[protocol.NodeID]map[string]uint64),
-		sup:           suppressor{threshold: int64(cfg.Options.MaxChangeKbps)},
+		indexDir:         indexDir,
+		cfg:              cfg,
+		db:               db,
+		clientName:       clientName,
+		clientVersion:    clientVersion,
+		repoCfgs:         make(map[string]config.RepositoryConfiguration),
+		repoFiles:        make(map[string]*files.Set),
+		repoNodes:        make(map[string][]protocol.NodeID),
+		nodeRepos:        make(map[protocol.NodeID][]string),
+		repoState:        make(map[string]repoState),
+		repoStateChanged: make(map[string]time.Time),
+		suppressor:       make(map[string]*suppressor),
+		protoConn:        make(map[protocol.NodeID]protocol.Connection),
+		rawConn:          make(map[protocol.NodeID]io.Closer),
+		nodeVer:          make(map[protocol.NodeID]string),
+		sentLocalVer:     make(map[protocol.NodeID]map[string]uint64),
+		sup:              suppressor{threshold: int64(cfg.Options.MaxChangeKbps)},
 	}
 
 	var timeout = 20 * 60 // seconds
@@ -322,16 +339,20 @@ func (m *Model) Index(nodeID protocol.NodeID, repo string, fs []protocol.FileInf
 	}
 
 	m.rmut.RLock()
-	if r, ok := m.repoFiles[repo]; ok {
+	r, ok := m.repoFiles[repo]
+	m.rmut.RUnlock()
+	if ok {
 		r.Replace(nodeID, fs)
 	} else {
 		l.Fatalf("Index for nonexistant repo %q", repo)
 	}
 	m.rmut.RUnlock()
 
-	events.Default.Log(events.RemoteIndexUpdated, map[string]string{
-		"node": nodeID.String(),
-		"repo": repo,
+	events.Default.Log(events.RemoteIndexUpdated, map[string]interface{}{
+		"node":    nodeID.String(),
+		"repo":    repo,
+		"items":   len(fs),
+		"version": r.LocalVersion(nodeID),
 	})
 }
 
@@ -348,16 +369,21 @@ func (m *Model) IndexUpdate(nodeID protocol.NodeID, repo string, fs []protocol.F
 	}
 
 	m.rmut.RLock()
-	if r, ok := m.repoFiles[repo]; ok {
+	r, ok := m.repoFiles[repo]
+	m.rmut.RUnlock()
+	m.rmut.RLock()
+	if ok {
 		r.Update(nodeID, fs)
 	} else {
 		l.Fatalf("IndexUpdate for nonexistant repo %q", repo)
 	}
 	m.rmut.RUnlock()
 
-	events.Default.Log(events.RemoteIndexUpdated, map[string]string{
-		"node": nodeID.String(),
-		"repo": repo,
+	events.Default.Log(events.RemoteIndexUpdated, map[string]interface{}{
+		"node":    nodeID.String(),
+		"repo":    repo,
+		"items":   len(fs),
+		"version": r.LocalVersion(nodeID),
 	})
 }
 
@@ -620,7 +646,13 @@ func (m *Model) updateLocal(repo string, f protocol.FileInfo) {
 	m.rmut.RLock()
 	m.repoFiles[repo].Update(protocol.LocalNodeID, []protocol.FileInfo{f})
 	m.rmut.RUnlock()
-	events.Default.Log(events.LocalIndexUpdated, map[string]string{"repo": repo})
+	events.Default.Log(events.LocalIndexUpdated, map[string]interface{}{
+		"repo":     repo,
+		"name":     f.Name,
+		"modified": time.Unix(f.Modified, 0),
+		"flags":    fmt.Sprintf("0%o", f.Flags),
+		"size":     f.Size(),
+	})
 }
 
 func (m *Model) requestGlobal(nodeID protocol.NodeID, repo, name string, offset int64, size int, hash []byte) ([]byte, error) {
@@ -797,26 +829,30 @@ func (m *Model) clusterConfig(node protocol.NodeID) protocol.ClusterConfigMessag
 
 func (m *Model) setState(repo string, state repoState) {
 	m.smut.Lock()
-	m.repoState[repo] = state
+	oldState := m.repoState[repo]
+	changed, ok := m.repoStateChanged[repo]
+	if state != oldState {
+		m.repoState[repo] = state
+		m.repoStateChanged[repo] = time.Now()
+		eventData := map[string]interface{}{
+			"repo": repo,
+			"to":   state.String(),
+		}
+		if ok {
+			eventData["duration"] = time.Since(changed).Seconds()
+			eventData["from"] = oldState.String()
+		}
+		events.Default.Log(events.StateChanged, eventData)
+	}
 	m.smut.Unlock()
 }
 
-func (m *Model) State(repo string) string {
+func (m *Model) State(repo string) (string, time.Time) {
 	m.smut.RLock()
 	state := m.repoState[repo]
+	changed := m.repoStateChanged[repo]
 	m.smut.RUnlock()
-	switch state {
-	case RepoIdle:
-		return "idle"
-	case RepoScanning:
-		return "scanning"
-	case RepoCleaning:
-		return "cleaning"
-	case RepoSyncing:
-		return "syncing"
-	default:
-		return "unknown"
-	}
+	return state.String(), changed
 }
 
 func (m *Model) Override(repo string) {