github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/logging/loggers/sort_logger.go (about)

     1  package loggers
     2  
     3  import (
     4  	"sort"
     5  
     6  	"github.com/go-kit/kit/log"
     7  )
     8  
     9  type sortableKeyvals struct {
    10  	indices map[string]int
    11  	keyvals []interface{}
    12  	len     int
    13  }
    14  
    15  func sortKeyvals(indices map[string]int, keyvals []interface{}) {
    16  	sort.Stable(sortable(indices, keyvals))
    17  }
    18  
    19  func sortable(indices map[string]int, keyvals []interface{}) *sortableKeyvals {
    20  	return &sortableKeyvals{
    21  		indices: indices,
    22  		keyvals: keyvals,
    23  		len:     len(keyvals) / 2,
    24  	}
    25  }
    26  
    27  func (skv *sortableKeyvals) Len() int {
    28  	return skv.len
    29  }
    30  
    31  // Less reports whether the element with
    32  // index i should sort before the element with index j.
    33  func (skv *sortableKeyvals) Less(i, j int) bool {
    34  	return skv.keyRank(i) < skv.keyRank(j)
    35  }
    36  
    37  // Swap swaps the elements with indexes i and j.
    38  func (skv *sortableKeyvals) Swap(i, j int) {
    39  	keyIdx, keyJdx := i*2, j*2
    40  	valIdx, valJdx := keyIdx+1, keyJdx+1
    41  	keyI, valI := skv.keyvals[keyIdx], skv.keyvals[valIdx]
    42  	skv.keyvals[keyIdx], skv.keyvals[valIdx] = skv.keyvals[keyJdx], skv.keyvals[valJdx]
    43  	skv.keyvals[keyJdx], skv.keyvals[valJdx] = keyI, valI
    44  }
    45  
    46  func (skv *sortableKeyvals) keyRank(i int) int {
    47  	// Check there is a key at this index
    48  	key, ok := skv.keyvals[i*2].(string)
    49  	if !ok {
    50  		// Sort keys not provided after those that have been but maintain relative order
    51  		return len(skv.indices) + i
    52  	}
    53  	// See if we have been provided an explicit rank/order for the key
    54  	idx, ok := skv.indices[key]
    55  	if !ok {
    56  		// Sort keys not provided after those that have been but maintain relative order
    57  		return len(skv.indices) + i
    58  	}
    59  	return idx
    60  }
    61  
    62  // Provides a logger that sorts key-values with keys in keys before other key-values
    63  func SortLogger(outputLogger log.Logger, keys ...string) log.Logger {
    64  	indices := make(map[string]int, len(keys))
    65  	for i, k := range keys {
    66  		indices[k] = i
    67  	}
    68  	return log.LoggerFunc(func(keyvals ...interface{}) error {
    69  		sortKeyvals(indices, keyvals)
    70  		return outputLogger.Log(keyvals...)
    71  	})
    72  }