github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/app/stats/command/command.go (about)

     1  package command
     2  
     3  //go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
     4  
     5  import (
     6  	"context"
     7  	"runtime"
     8  	"time"
     9  
    10  	grpc "google.golang.org/grpc"
    11  
    12  	core "github.com/v2fly/v2ray-core/v5"
    13  	"github.com/v2fly/v2ray-core/v5/app/stats"
    14  	"github.com/v2fly/v2ray-core/v5/common"
    15  	"github.com/v2fly/v2ray-core/v5/common/strmatcher"
    16  	feature_stats "github.com/v2fly/v2ray-core/v5/features/stats"
    17  )
    18  
    19  // statsServer is an implementation of StatsService.
    20  type statsServer struct {
    21  	stats     feature_stats.Manager
    22  	startTime time.Time
    23  }
    24  
    25  func NewStatsServer(manager feature_stats.Manager) StatsServiceServer {
    26  	return &statsServer{
    27  		stats:     manager,
    28  		startTime: time.Now(),
    29  	}
    30  }
    31  
    32  func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {
    33  	c := s.stats.GetCounter(request.Name)
    34  	if c == nil {
    35  		return nil, newError(request.Name, " not found.")
    36  	}
    37  	var value int64
    38  	if request.Reset_ {
    39  		value = c.Set(0)
    40  	} else {
    41  		value = c.Value()
    42  	}
    43  	return &GetStatsResponse{
    44  		Stat: &Stat{
    45  			Name:  request.Name,
    46  			Value: value,
    47  		},
    48  	}, nil
    49  }
    50  
    51  func (s *statsServer) QueryStats(ctx context.Context, request *QueryStatsRequest) (*QueryStatsResponse, error) {
    52  	mgroup := &strmatcher.LinearIndexMatcher{}
    53  	if request.Pattern != "" {
    54  		request.Patterns = append(request.Patterns, request.Pattern)
    55  	}
    56  	t := strmatcher.Substr
    57  	if request.Regexp {
    58  		t = strmatcher.Regex
    59  	}
    60  	for _, p := range request.Patterns {
    61  		m, err := t.New(p)
    62  		if err != nil {
    63  			return nil, err
    64  		}
    65  		mgroup.Add(m)
    66  	}
    67  
    68  	response := &QueryStatsResponse{}
    69  
    70  	manager, ok := s.stats.(*stats.Manager)
    71  	if !ok {
    72  		return nil, newError("QueryStats only works its own stats.Manager.")
    73  	}
    74  
    75  	manager.VisitCounters(func(name string, c feature_stats.Counter) bool {
    76  		if mgroup.Size() == 0 || len(mgroup.Match(name)) > 0 {
    77  			var value int64
    78  			if request.Reset_ {
    79  				value = c.Set(0)
    80  			} else {
    81  				value = c.Value()
    82  			}
    83  			response.Stat = append(response.Stat, &Stat{
    84  				Name:  name,
    85  				Value: value,
    86  			})
    87  		}
    88  		return true
    89  	})
    90  
    91  	return response, nil
    92  }
    93  
    94  func (s *statsServer) GetSysStats(ctx context.Context, request *SysStatsRequest) (*SysStatsResponse, error) {
    95  	var rtm runtime.MemStats
    96  	runtime.ReadMemStats(&rtm)
    97  
    98  	uptime := time.Since(s.startTime)
    99  
   100  	response := &SysStatsResponse{
   101  		Uptime:       uint32(uptime.Seconds()),
   102  		NumGoroutine: uint32(runtime.NumGoroutine()),
   103  		Alloc:        rtm.Alloc,
   104  		TotalAlloc:   rtm.TotalAlloc,
   105  		Sys:          rtm.Sys,
   106  		Mallocs:      rtm.Mallocs,
   107  		Frees:        rtm.Frees,
   108  		LiveObjects:  rtm.Mallocs - rtm.Frees,
   109  		NumGC:        rtm.NumGC,
   110  		PauseTotalNs: rtm.PauseTotalNs,
   111  	}
   112  
   113  	return response, nil
   114  }
   115  
   116  func (s *statsServer) mustEmbedUnimplementedStatsServiceServer() {}
   117  
   118  type service struct {
   119  	statsManager feature_stats.Manager
   120  }
   121  
   122  func (s *service) Register(server *grpc.Server) {
   123  	RegisterStatsServiceServer(server, NewStatsServer(s.statsManager))
   124  }
   125  
   126  func init() {
   127  	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
   128  		s := new(service)
   129  
   130  		core.RequireFeatures(ctx, func(sm feature_stats.Manager) {
   131  			s.statsManager = sm
   132  		})
   133  
   134  		return s, nil
   135  	}))
   136  }