예제 #1
0
파일: flow.go 프로젝트: jgcsco/spigo
// Terminate a flow, flushing output and freeing the request id to keep the map smaller
func End(msg gotocol.Message, resphist, servhist, rthist metrics.Histogram) {
	if !archaius.Conf.Collect {
		return
	}
	var cs, sr, ss, cr int64
	// find the annotations for the client send time and the client receive time
	for _, a := range flowmap[msg.Ctx.Trace] {
		if a.Value == CS.String() {
			cs = a.Timestamp
		}
		if a.Value == SR.String() {
			sr = a.Timestamp
		}
		if a.Value == SS.String() {
			ss = a.Timestamp
		}
		if a.Value == CR.String() {
			cr = a.Timestamp
		}
	}
	if cs > 0 && cr > 0 { // response time measured at the client
		collect.Measure(resphist, time.Unix(0, cr).Sub(time.Unix(0, cs)))
	}
	if ss > 0 && sr > 0 { // service time measured at the server
		collect.Measure(servhist, time.Unix(0, ss).Sub(time.Unix(0, sr)))
	}
	if cs > 0 && cr > 0 && ss > 0 && sr > 0 { // network time sum of each direction
		collect.Measure(rthist, time.Unix(0, sr).Sub(time.Unix(0, cs))+time.Unix(0, cr).Sub(time.Unix(0, ss)))
	}
}
예제 #2
0
파일: fsm.go 프로젝트: jgcsco/spigo
// Shutdown fsm and pirates
func shutdown() {
	var msg gotocol.Message
	hist := collect.NewHist("fsm")
	// wait until the delay has finished
	if archaius.Conf.RunDuration >= time.Millisecond {
		time.Sleep(archaius.Conf.RunDuration)
	}
	log.Println("fsm: Shutdown")
	for _, noodle := range noodles {
		gotocol.Message{gotocol.Goodbye, nil, time.Now(), gotocol.NilContext, "beer volcano"}.GoSend(noodle)
	}
	for len(noodles) > 0 {
		msg = <-listener
		collect.Measure(hist, time.Since(msg.Sent))
		if archaius.Conf.Msglog {
			log.Printf("fsm: %v\n", msg)
		}
		switch msg.Imposition {
		case gotocol.Goodbye:
			delete(noodles, msg.Intention)
			if archaius.Conf.Msglog {
				log.Printf("fsm: Pirate population: %v    \n", len(noodles))
			}
		}
	}
	collect.Save()
	log.Println("fsm: Exit")
}
예제 #3
0
파일: flow.go 프로젝트: jgcsco/spigo
// common code for instrumenting requests
func Instrument(msg gotocol.Message, name string, hist metrics.Histogram) {
	received := time.Now()
	collect.Measure(hist, received.Sub(msg.Sent))
	if archaius.Conf.Msglog {
		log.Printf("%v: %v\n", name, msg)
	}
	if msg.Ctx != gotocol.NilContext {
		AnnotateReceive(msg, name, received) // store the annotation for this request
	}
}
예제 #4
0
파일: eureka.go 프로젝트: jgcsco/spigo
// Start eureka discovery service and set name directly
func Start(listener chan gotocol.Message, name string) {
	// use a waitgroup so whoever starts eureka can tell it's ready and when stopping that the logs have been flushed
	Wg.Add(1)
	defer Wg.Done()
	var msg gotocol.Message
	var ok bool
	hist := collect.NewHist(name)
	microservices := make(map[string]chan gotocol.Message, archaius.Conf.Dunbar)
	eurekaservices := make(map[string]chan gotocol.Message, 2)
	metadata := make(map[string]meta, archaius.Conf.Dunbar)
	lastrequest := make(map[callback]time.Time) // remember time of last request for a service from this requestor
	log.Println(name + ": starting")
	for {
		msg, ok = <-listener
		collect.Measure(hist, time.Since(msg.Sent))
		if !ok {
			break // channel was closed
		}
		//commented out because name service traffic is too much noise in the log
		//if archaius.Conf.Msglog {
		//	log.Printf("%v(backlog %v): %v\n", name, len(listener), msg)
		//}
		switch msg.Imposition {
		// used to wire up connections to other eureka nodes only
		case gotocol.NameDrop:
			if msg.Intention != name { // don't talk to myself
				eurekaservices[msg.Intention] = msg.ResponseChan
			}
		// for new nodes record the data, replicate and maybe pass on to be logged
		case gotocol.Put:
			if microservices[msg.Intention] == nil { // ignore duplicate requests
				microservices[msg.Intention] = msg.ResponseChan
				metadata[msg.Intention] = meta{true, msg.Sent}
				// replicate request, everyone ends up with the same timestamp for state change of this service
				for _, c := range eurekaservices {
					gotocol.Message{gotocol.Replicate, msg.ResponseChan, msg.Sent, gotocol.NilContext, msg.Intention}.GoSend(c)
				}
				if edda.Logchan != nil {
					edda.Logchan <- msg
				}
			}
		case gotocol.Replicate:
			if microservices[msg.Intention] == nil { // ignore multiple requests
				microservices[msg.Intention] = msg.ResponseChan
				metadata[msg.Intention] = meta{true, msg.Sent}
			}
		case gotocol.Inform:
			// don't store edges in discovery but do log them
			if edda.Logchan != nil {
				edda.Logchan <- msg
			}
		case gotocol.GetRequest:
			if msg.Intention == "" {
				log.Fatal(name + ": empty GetRequest")
			}
			if microservices[msg.Intention] != nil { // matched a unique full name
				gotocol.Message{gotocol.NameDrop, microservices[msg.Intention], time.Now(), gotocol.NilContext, msg.Intention}.GoSend(msg.ResponseChan)
				break
			}
			for n, ch := range microservices { // respond with all the online names that match the service component
				if names.Service(n) == msg.Intention {
					// if there was an update for the looked up service since last check
					// log.Printf("%v: matching %v with %v, last: %v metadata: %v\n", name, n, msg.Intention, lastrequest[callback{n, msg.ResponseChan}], metadata[n].registered)
					if metadata[n].registered.After(lastrequest[callback{n, msg.ResponseChan}]) {
						if metadata[n].online {
							gotocol.Message{gotocol.NameDrop, ch, time.Now(), gotocol.NilContext, n}.GoSend(msg.ResponseChan)
						} else {
							//log.Printf("%v:Forget %v\n", name, n)
							gotocol.Message{gotocol.Forget, ch, time.Now(), gotocol.NilContext, n}.GoSend(msg.ResponseChan)
						}
					}
					// remember for next time
					lastrequest[callback{n, msg.ResponseChan}] = msg.Sent
				}
			}
		case gotocol.Delete: // remove a node
			if microservices[msg.Intention] != nil { // matched a unique full name
				metadata[msg.Intention] = meta{false, time.Now()}
				// replicate request
				for _, c := range eurekaservices {
					gotocol.Message{gotocol.Replicate, nil, time.Now(), gotocol.NilContext, msg.Intention}.GoSend(c)
				}
				if edda.Logchan != nil {
					edda.Logchan <- msg
				}
			}
		case gotocol.Goodbye:
			gotocol.Message{gotocol.Goodbye, nil, time.Now(), gotocol.NilContext, name}.GoSend(msg.ResponseChan)
			log.Println(name + ": closing")
			return
		}
	}
}
예제 #5
0
파일: pirate.go 프로젝트: jgcsco/spigo
// Start the pirate, all configuration and state is sent via messages
func Start(listener chan gotocol.Message) {
	dunbar := 10 // starting point for how many buddies to remember
	// remember the channel to talk to named buddies
	buddies := make(map[string]chan gotocol.Message, dunbar)
	// remember who sent GoldCoin and how much, to buy favors
	benefactors := make(map[string]int, dunbar)
	var booty int                   // current GoldCoin balance
	var fsm chan gotocol.Message    // remember how to talk back to creator
	var name string                 // remember my name
	var logger chan gotocol.Message // if set, send updates
	var chatrate time.Duration
	hist := collect.NewHist("")
	chatTicker := time.NewTicker(time.Hour)
	chatTicker.Stop()
	for {
		select {
		case msg := <-listener:
			collect.Measure(hist, time.Since(msg.Sent))
			if archaius.Conf.Msglog {
				log.Printf("%v: %v\n", name, msg)
			}
			switch msg.Imposition {
			case gotocol.Hello:
				if name == "" {
					// if I don't have a name yet remember what I've been named
					fsm = msg.ResponseChan // remember how to talk to my namer
					name = msg.Intention   // message body is my name
					hist = collect.NewHist(name)
				}
			case gotocol.Inform:
				// remember where to send updates
				logger = handlers.Inform(msg, name, listener)
			case gotocol.NameDrop:
				// don't remember too many buddies and don't talk to myself
				buddy := msg.Intention // message body is buddy name
				if len(buddies) < dunbar && buddy != name {
					// remember how to talk to this buddy
					buddies[buddy] = msg.ResponseChan // message channel is buddy's listener
					if logger != nil {
						// if it's setup, tell the logger I have a new buddy to talk to
						logger <- gotocol.Message{gotocol.Inform, listener, time.Now(), gotocol.NilContext, name + " " + buddy}
					}
				}
			case gotocol.Chat:
				// setup the ticker to run at the specified rate
				d, e := time.ParseDuration(msg.Intention)
				if e == nil && d >= time.Millisecond && d <= time.Hour {
					chatrate = d
					chatTicker = time.NewTicker(chatrate)
					// assume we got paid before we started chatting
					rand.Seed(int64(booty))
				}
			case gotocol.GoldCoin:
				var coin int
				_, e := fmt.Sscanf(msg.Intention, "%d", &coin)
				if e == nil && coin > 0 {
					booty += coin
					for name, ch := range buddies {
						if ch == msg.ResponseChan {
							benefactors[name] += coin
						}
					}
				}
			case gotocol.Goodbye:
				if archaius.Conf.Msglog {
					log.Printf("%v: Going away with %v gold coins, chatting every %v\n", name, booty, chatrate)
				}
				gotocol.Message{gotocol.Goodbye, nil, time.Now(), gotocol.NilContext, name}.GoSend(fsm)
				return
			}
		case <-chatTicker.C:
			if rand.Intn(100) < 50 { // 50% of the time
				// use Namedrop to tell the last buddy about the first
				var firstBuddyName string
				var firstBuddyChan, lastBuddyChan chan gotocol.Message
				if len(buddies) >= 2 {
					for name, ch := range buddies {
						if firstBuddyName == "" {
							firstBuddyName = name
							firstBuddyChan = ch
						} else {
							lastBuddyChan = ch
						}
						gotocol.Message{gotocol.NameDrop, firstBuddyChan, time.Now(), gotocol.NewTrace(), firstBuddyName}.GoSend(lastBuddyChan)
					}
				}
			} else {
				// send a buddy some money
				if booty > 0 {
					donation := rand.Intn(booty)
					luckyNumber := rand.Intn(len(buddies))
					if donation > 0 {
						for _, ch := range buddies {
							if luckyNumber == 0 {
								gotocol.Message{gotocol.GoldCoin, listener, time.Now(), gotocol.NewTrace(), fmt.Sprintf("%d", donation)}.GoSend(ch)
								booty -= donation
								break
							} else {
								luckyNumber--
							}
						}
					}
				}
			}
		}
	}
}
예제 #6
0
파일: edda.go 프로젝트: jgcsco/spigo
// Start edda, to listen for logging data from services
func Start(name string) {
	// use a waitgroup so whoever starts edda can tell the logs have been flushed
	Wg.Add(1)
	defer Wg.Done()
	if Logchan == nil {
		return
	}
	var msg gotocol.Message
	microservices := make(map[string]bool, archaius.Conf.Dunbar)
	edges := make(map[string]bool, archaius.Conf.Dunbar)
	var ok bool
	hist := collect.NewHist(name)
	log.Println(name + ": starting")
	if archaius.Conf.GraphmlFile != "" {
		graphml.Setup(archaius.Conf.GraphmlFile)
	}
	if archaius.Conf.GraphjsonFile != "" {
		graphjson.Setup(archaius.Conf.GraphjsonFile)
	}
	if archaius.Conf.Neo4jURL != "" {
		graphneo4j.Setup(archaius.Conf.Neo4jURL)
	}
	for {
		msg, ok = <-Logchan
		collect.Measure(hist, time.Since(msg.Sent))
		if !ok {
			break // channel was closed
		}
		if archaius.Conf.Msglog {
			log.Printf("%v(backlog %v): %v\n", name, len(Logchan), msg)
		}
		switch msg.Imposition {
		case gotocol.Inform:
			edge := names.FilterEdge(msg.Intention)
			if edges[edge] == false { // only log an edge once
				edges[edge] = true
				graphml.WriteEdge(edge)
				graphjson.WriteEdge(edge, msg.Sent)
				graphneo4j.WriteEdge(strings.Replace(msg.Intention, "-", "_", -1), msg.Sent)
			}
		case gotocol.Put:
			node := names.FilterNode(msg.Intention)
			if microservices[node] == false { // only log a node once
				microservices[node] = true
				graphml.WriteNode(node + " " + names.Package(msg.Intention))
				graphjson.WriteNode(node+" "+names.Package(msg.Intention), msg.Sent)
				graphneo4j.WriteNode(strings.Replace(msg.Intention, "-", "_", -1)+" "+names.Package(msg.Intention), msg.Sent)
			}
		case gotocol.Forget: // forget the edge
			// problem here in that edges may be reported multiple times from several sources
			// however after filtering all matching edges are reported as forgotten when the first is
			// need to maintain the full model and a filtered model with counts
			edge := names.FilterEdge(msg.Intention)
			if edges[edge] == true { // only remove an edge once
				edges[edge] = false
				graphjson.WriteForget(edge, msg.Sent)
			}
		case gotocol.Delete: // remove the node
			node := names.FilterNode(msg.Intention)
			if microservices[node] == true { // only remove nodes that exist, and only log it once
				microservices[node] = false
				graphjson.WriteDone(node, msg.Sent)
			}
		}
	}
	log.Println(name + ": closing")
	graphml.Close()
	graphjson.Close()
	graphneo4j.Close()
}