code: func (sb *StatsdBuffer) collector() {
  	// on a panic event, flush all the pending stats before panicking
  	defer func(sb *StatsdBuffer) {
  		if r := recover(); r != nil {
  			sb.Logger.Println("Caught panic, flushing stats before throwing the panic again")
  			err := sb.flush()
  			if nil != err {
  				sb.Logger.Println("Error flushing stats", err.Error())
  			}
  			panic(r)
  		}
  	}(sb)
  
  	keyFor := initMemoisedKeyMap() // avoid allocations (https://gobyexample.com/closures)
  
  	ticker := time.NewTicker(sb.flushInterval)
  
  	for {
  		select {
  		case <-ticker.C:
  			//sb.Logger.Println("Flushing stats")
  			err := sb.flush()
  			if nil != err {
  				sb.Logger.Println("Error flushing stats", err.Error())
  			}
  		case e := <-sb.eventChannel:
  			//sb.Logger.Println("Received ", e.String())
  			// issue #28: unable to use Incr and PrecisionTiming with the same key (also fixed #27)
  			k := keyFor(e.TypeString(), e.Key()) // avoid allocations
  			if e2, ok := sb.events[k]; ok {
  				//sb.Logger.Println("Updating existing event")
  				err := e2.Update(e)
  				if nil != err {
  					sb.Logger.Println("Error updating stats", err.Error())
  				}
  				sb.events[k] = e2
  			} else {
  				//sb.Logger.Println("Adding new event")
  				sb.events[k] = e
  			}
  		case c := <-sb.closeChannel:
  			if sb.Verbose {
  				sb.Logger.Println("Asked to terminate. Flushing stats before returning.")
  			}
  			c.reply <- sb.flush()
  			return
  		}
  	}
  }
docs: // handle flushes and updates in one single thread (instead of locking the events map)