github.com/kaituanwang/hyperledger@v2.0.1+incompatible/orderer/consensus/kafka/logger.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package kafka
     8  
     9  import (
    10  	"fmt"
    11  	"strings"
    12  	"sync"
    13  
    14  	"github.com/Shopify/sarama"
    15  	"github.com/hyperledger/fabric/common/flogging"
    16  	"go.uber.org/zap"
    17  )
    18  
    19  var logger = flogging.MustGetLogger("orderer.consensus.kafka")
    20  var saramaLogger eventLogger
    21  
    22  // init initializes the samara logger
    23  func init() {
    24  	loggingProvider := flogging.MustGetLogger("orderer.consensus.kafka.sarama")
    25  	saramaEventLogger := &saramaLoggerImpl{
    26  		logger: loggingProvider.WithOptions(zap.AddCallerSkip(3)),
    27  		eventListenerSupport: &eventListenerSupport{
    28  			listeners: make(map[string][]chan string),
    29  		},
    30  	}
    31  	sarama.Logger = saramaEventLogger
    32  	saramaLogger = saramaEventLogger
    33  }
    34  
    35  // init starts a go routine that detects a possible configuration issue
    36  func init() {
    37  	listener := saramaLogger.NewListener("insufficient data to decode packet")
    38  	go func() {
    39  		for {
    40  			select {
    41  			case <-listener:
    42  				logger.Critical("Unable to decode a Kafka packet. Usually, this " +
    43  					"indicates that the Kafka.Version specified in the orderer " +
    44  					"configuration is incorrectly set to a version which is newer than " +
    45  					"the actual Kafka broker version.")
    46  			}
    47  		}
    48  	}()
    49  }
    50  
    51  // eventLogger adapts a Logger to the sarama.Logger interface.
    52  // Additionally, listeners can be registered to be notified when a substring has
    53  // been logged.
    54  type eventLogger interface {
    55  	sarama.StdLogger
    56  	NewListener(substr string) <-chan string
    57  	RemoveListener(substr string, listener <-chan string)
    58  }
    59  
    60  type debugger interface {
    61  	Debug(...interface{})
    62  }
    63  
    64  type saramaLoggerImpl struct {
    65  	logger               debugger
    66  	eventListenerSupport *eventListenerSupport
    67  }
    68  
    69  func (l saramaLoggerImpl) Print(args ...interface{}) {
    70  	l.print(fmt.Sprint(args...))
    71  }
    72  
    73  func (l saramaLoggerImpl) Printf(format string, args ...interface{}) {
    74  	l.print(fmt.Sprintf(format, args...))
    75  }
    76  
    77  func (l saramaLoggerImpl) Println(args ...interface{}) {
    78  	l.print(fmt.Sprintln(args...))
    79  }
    80  
    81  func (l saramaLoggerImpl) print(message string) {
    82  	l.eventListenerSupport.fire(message)
    83  	l.logger.Debug(message)
    84  }
    85  
    86  // this should be more than enough for a well behaved listener
    87  const listenerChanSize = 100
    88  
    89  func (l saramaLoggerImpl) NewListener(substr string) <-chan string {
    90  	listener := make(chan string, listenerChanSize)
    91  	l.eventListenerSupport.addListener(substr, listener)
    92  	return listener
    93  }
    94  
    95  func (l saramaLoggerImpl) RemoveListener(substr string, listener <-chan string) {
    96  	l.eventListenerSupport.removeListener(substr, listener)
    97  }
    98  
    99  // eventListenerSupport maintains a map of substrings to a list of listeners
   100  // interested in receiving a notification when the substring is logged.
   101  type eventListenerSupport struct {
   102  	sync.Mutex
   103  	listeners map[string][]chan string
   104  }
   105  
   106  // addListener adds a listener to the list of listeners for the specified substring
   107  func (b *eventListenerSupport) addListener(substr string, listener chan string) {
   108  	b.Lock()
   109  	defer b.Unlock()
   110  	if listeners, ok := b.listeners[substr]; ok {
   111  		b.listeners[substr] = append(listeners, listener)
   112  	} else {
   113  		b.listeners[substr] = []chan string{listener}
   114  	}
   115  }
   116  
   117  // fire sends the specified message to each listener that is registered with
   118  // a substring contained in the message
   119  func (b *eventListenerSupport) fire(message string) {
   120  	b.Lock()
   121  	defer b.Unlock()
   122  	for substr, listeners := range b.listeners {
   123  		if strings.Contains(message, substr) {
   124  			for _, listener := range listeners {
   125  				listener <- message
   126  			}
   127  		}
   128  	}
   129  }
   130  
   131  // addListener removes a listener from the list of listeners for the specified substring
   132  func (b *eventListenerSupport) removeListener(substr string, listener <-chan string) {
   133  	b.Lock()
   134  	defer b.Unlock()
   135  	if listeners, ok := b.listeners[substr]; ok {
   136  		for i, l := range listeners {
   137  			if l == listener {
   138  				copy(listeners[i:], listeners[i+1:])
   139  				listeners[len(listeners)-1] = nil
   140  				b.listeners[substr] = listeners[:len(listeners)-1]
   141  			}
   142  		}
   143  	}
   144  }