github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/app/logevents/provider.go (about)

     1  package logevents
     2  
     3  import (
     4  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/server"
     5  	"github.com/fibonacci-chain/fbc/libs/system"
     6  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
     7  	"github.com/fibonacci-chain/fbc/libs/tendermint/types"
     8  	"github.com/spf13/viper"
     9  	"sync"
    10  	"time"
    11  )
    12  
    13  type provider struct {
    14  	eventChan       chan *KafkaMsg
    15  	identity        string
    16  	logServerUrl    string
    17  	logger          log.Logger
    18  	kafka           *logClient
    19  	subscriberAlive bool
    20  
    21  	mutex         sync.Mutex
    22  	lastHeartbeat time.Time
    23  }
    24  
    25  func NewProvider(logger log.Logger) log.Subscriber {
    26  	url := viper.GetString(server.FlagLogServerUrl)
    27  	if len(url) == 0 {
    28  		logger.Info("Publishing logs is disabled")
    29  		return nil
    30  	}
    31  
    32  	p := &provider{
    33  		eventChan:    make(chan *KafkaMsg, 1000),
    34  		logServerUrl: url,
    35  		logger:       logger.With("module", "provider"),
    36  	}
    37  	p.init()
    38  	return p
    39  }
    40  
    41  func (p *provider) init() {
    42  
    43  	var err error
    44  	p.identity, err = system.GetIpAddr(viper.GetBool(types.FlagAppendPid))
    45  
    46  	if len(p.identity) == 0 {
    47  		panic("Invalid identity")
    48  	}
    49  
    50  	if err != nil {
    51  		p.logger.Error("Failed to set identity", "err", err)
    52  		return
    53  	}
    54  
    55  	role := viper.GetString("consensus-role")
    56  	if len(role) > 0 {
    57  		p.identity = role
    58  	}
    59  
    60  	p.kafka = newLogClient(p.logServerUrl, FBCLogTopic, HeartbeatTopic, p.identity)
    61  
    62  	p.logger.Info("Provider init", "url", p.logServerUrl, "id", p.identity)
    63  
    64  	go p.eventRoutine()
    65  	go p.expiredRoutine()
    66  	go p.heartbeatRoutine()
    67  }
    68  
    69  func (p *provider) AddEvent(buf log.LogBuf) {
    70  	if !p.subscriberAlive {
    71  		return
    72  	}
    73  
    74  	msg := KafkaMsgPool.Get().(*KafkaMsg)
    75  	msg.Data = buf.String()
    76  	p.eventChan <- msg
    77  }
    78  
    79  func (p *provider) eventRoutine() {
    80  	for event := range p.eventChan {
    81  		p.eventHandler(event)
    82  	}
    83  }
    84  
    85  func (p *provider) heartbeatInterval() time.Duration {
    86  	p.mutex.Lock()
    87  	defer p.mutex.Unlock()
    88  	return time.Now().Sub(p.lastHeartbeat)
    89  }
    90  
    91  func (p *provider) keepAlive() {
    92  	p.mutex.Lock()
    93  	defer p.mutex.Unlock()
    94  	p.lastHeartbeat = time.Now()
    95  	p.subscriberAlive = true
    96  }
    97  
    98  func (p *provider) expiredRoutine() {
    99  	ticker := time.NewTicker(ExpiredInterval)
   100  	for range ticker.C {
   101  		interval := p.heartbeatInterval()
   102  		if interval > ExpiredInterval {
   103  			p.subscriberAlive = false
   104  			p.logger.Info("Subscriber expired", "not-seen-for", interval)
   105  		}
   106  	}
   107  }
   108  
   109  func (p *provider) heartbeatRoutine() {
   110  	for {
   111  		key, m, err := p.kafka.recv()
   112  		if err != nil {
   113  			p.logger.Error("Provider heartbeat routine", "err", err)
   114  			continue
   115  		}
   116  		p.logger.Info("Provider heartbeat routine",
   117  			"from", key,
   118  			"value", m.Data,
   119  			//"topic", m.Topic,
   120  			"err", err,
   121  		)
   122  		p.keepAlive()
   123  	}
   124  }
   125  
   126  func (p *provider) eventHandler(msg *KafkaMsg) {
   127  	// DO NOT use p.logger to log anything in this method!!!
   128  	defer KafkaMsgPool.Put(msg)
   129  	p.kafka.send(p.identity, msg)
   130  }