github.com/matrixorigin/matrixone@v1.2.0/pkg/util/metric/mometric/stats_log_writer.go (about)

     1  // Copyright 2023 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package mometric
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"sync"
    21  	"sync/atomic"
    22  	"time"
    23  
    24  	"github.com/matrixorigin/matrixone/pkg/common/log"
    25  	"github.com/matrixorigin/matrixone/pkg/objectio"
    26  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    27  	"github.com/matrixorigin/matrixone/pkg/util/metric/stats"
    28  )
    29  
    30  type StatsLogWriter struct {
    31  	isRunning int32
    32  	cancel    context.CancelFunc
    33  	stopWg    sync.WaitGroup
    34  
    35  	registry       *stats.Registry
    36  	gatherInterval time.Duration
    37  
    38  	logger *log.MOLogger
    39  }
    40  
    41  func newStatsLogWriter(registry *stats.Registry, logger *log.MOLogger, gatherInterval time.Duration) *StatsLogWriter {
    42  	return &StatsLogWriter{
    43  		registry:       registry,
    44  		gatherInterval: gatherInterval,
    45  		logger:         logger,
    46  	}
    47  }
    48  
    49  func (e *StatsLogWriter) Start(inputCtx context.Context) bool {
    50  	if atomic.SwapInt32(&e.isRunning, 1) == 1 {
    51  		return false
    52  	}
    53  	ctx, cancel := context.WithCancel(inputCtx)
    54  	e.cancel = cancel
    55  	e.stopWg.Add(1)
    56  	go func() {
    57  		defer e.stopWg.Done()
    58  		ticker := time.NewTicker(e.gatherInterval)
    59  		defer ticker.Stop()
    60  		for {
    61  			select {
    62  			case <-ticker.C:
    63  				e.gatherAndWrite(ctx)
    64  			case <-ctx.Done():
    65  				return
    66  			}
    67  		}
    68  	}()
    69  	return true
    70  }
    71  
    72  func (e *StatsLogWriter) Stop(_ bool) (<-chan struct{}, bool) {
    73  	if atomic.SwapInt32(&e.isRunning, 0) == 0 {
    74  		return nil, false
    75  	}
    76  	e.cancel()
    77  	stopCh := make(chan struct{})
    78  	go func() { e.stopWg.Wait(); close(stopCh) }()
    79  	return stopCh, true
    80  }
    81  
    82  // gatherAndWriter gathers all the logs from Stats and Writes to Log
    83  // Example log output:
    84  // 2023/03/15 02:37:31.767463 -0500 INFO cn-service mometric/stats_log_writer.go:86 MockServiceStats stats  {"uuid": "test", "reads": 2, "hits": 1}
    85  // 2023/03/15 02:37:33.767659 -0500 INFO cn-service mometric/stats_log_writer.go:86 MockServiceStats stats  {"uuid": "test", "reads": 0, "hits": 0}
    86  // 2023/03/15 02:37:35.767608 -0500 INFO cn-service mometric/stats_log_writer.go:86 MockServiceStats stats  {"uuid": "test", "reads": 0, "hits": 0}
    87  func (e *StatsLogWriter) gatherAndWrite(ctx context.Context) {
    88  	statsFamilies := e.registry.ExportLog()
    89  	for statsFName, statsFamily := range statsFamilies {
    90  		if len(statsFamily) > 1 {
    91  			e.logger.Info(statsFName, statsFamily...)
    92  		}
    93  	}
    94  
    95  	// logging block read statistics info here
    96  	v := ctx.Value(ServiceTypeKey).(string)
    97  	if v == metadata.ServiceType_name[int32(metadata.ServiceType_CN)] || v == LaunchMode {
    98  		e.writeBlkReadStats()
    99  	}
   100  }
   101  
   102  func (e *StatsLogWriter) writeBlkReadStats() {
   103  	blkHit, blkTotal := objectio.BlkReadStats.BlkCacheHitStats.ExportW()
   104  	blkHitRate := float32(1)
   105  	if blkTotal != 0 {
   106  		blkHitRate = float32(blkHit) / float32(blkTotal)
   107  	}
   108  
   109  	entryHit, entryTotal := objectio.BlkReadStats.EntryCacheHitStats.ExportW()
   110  	entryHitRate := float32(1)
   111  	if entryTotal != 0 {
   112  		entryHitRate = float32(entryHit) / float32(entryTotal)
   113  	}
   114  
   115  	readerNum, blkNum := objectio.BlkReadStats.BlksByReaderStats.ExportW()
   116  	blksInEachReader := float32(1)
   117  	if readerNum != 0 {
   118  		blksInEachReader = float32(blkNum) / float32(readerNum)
   119  	}
   120  
   121  	e.logger.Info(fmt.Sprintf("duration: %d, "+
   122  		"blk hit rate: %d/%d=%.4f, entry hit rate: %d/%d=%.4f, (average) blks in each reader: %d/%d=%.4f",
   123  		e.gatherInterval,
   124  		blkHit, blkTotal, blkHitRate,
   125  		entryHit, entryTotal, entryHitRate,
   126  		blkNum, readerNum, blksInEachReader))
   127  
   128  }