github.com/asynkron/protoactor-go@v0.0.0-20240308120642-ef91a6abee75/metrics/actor_metrics.go (about)

     1  // Copyright (C) 2017 - 2022 Asynkron.se <http://www.asynkron.se>
     2  
     3  package metrics
     4  
     5  import (
     6  	"fmt"
     7  	"log/slog"
     8  	"sync"
     9  
    10  	"go.opentelemetry.io/otel"
    11  	"go.opentelemetry.io/otel/metric"
    12  )
    13  
    14  const LibName string = "protoactor"
    15  
    16  type ActorMetrics struct {
    17  	// Mutual Exclusion Primitive to use with ActorMailboxLength
    18  	mu *sync.Mutex
    19  
    20  	// MetricsID
    21  	ID string
    22  
    23  	// Actors
    24  	ActorFailureCount            metric.Int64Counter
    25  	ActorMailboxLength           metric.Int64ObservableGauge
    26  	ActorMessageReceiveHistogram metric.Float64Histogram
    27  	ActorRestartedCount          metric.Int64Counter
    28  	ActorSpawnCount              metric.Int64Counter
    29  	ActorStoppedCount            metric.Int64Counter
    30  
    31  	// Deadletters
    32  	DeadLetterCount metric.Int64Counter
    33  
    34  	// Futures
    35  	FuturesStartedCount   metric.Int64Counter
    36  	FuturesCompletedCount metric.Int64Counter
    37  	FuturesTimedOutCount  metric.Int64Counter
    38  
    39  	// Threadpool
    40  	ThreadPoolLatency metric.Int64Histogram
    41  }
    42  
    43  // NewActorMetrics creates a new ActorMetrics value and returns a pointer to it
    44  func NewActorMetrics(logger *slog.Logger) *ActorMetrics {
    45  	instruments := newInstruments(logger)
    46  	return instruments
    47  }
    48  
    49  // newInstruments will create instruments using a meter from
    50  // the given provider p
    51  func newInstruments(logger *slog.Logger) *ActorMetrics {
    52  	meter := otel.Meter(LibName)
    53  	instruments := ActorMetrics{mu: &sync.Mutex{}}
    54  
    55  	var err error
    56  
    57  	if instruments.ActorFailureCount, err = meter.Int64Counter(
    58  		"protoactor_actor_failure_count",
    59  		metric.WithDescription("Number of actor failures"),
    60  		metric.WithUnit("1"),
    61  	); err != nil {
    62  		err = fmt.Errorf("failed to create ActorFailureCount instrument, %w", err)
    63  		logger.Error(err.Error(), slog.Any("error", err))
    64  	}
    65  
    66  	if instruments.ActorMessageReceiveHistogram, err = meter.Float64Histogram(
    67  		"protoactor_actor_message_receive_duration_seconds",
    68  		metric.WithDescription("Actor's messages received duration in seconds"),
    69  	); err != nil {
    70  		err = fmt.Errorf("failed to create ActorMessageReceiveHistogram instrument, %w", err)
    71  		logger.Error(err.Error(), slog.Any("error", err))
    72  	}
    73  
    74  	if instruments.ActorRestartedCount, err = meter.Int64Counter(
    75  		"protoactor_actor_restarted_count",
    76  		metric.WithDescription("Number of actors restarts"),
    77  		metric.WithUnit("1"),
    78  	); err != nil {
    79  		err = fmt.Errorf("failed to create ActorRestartedCount instrument, %w", err)
    80  		logger.Error(err.Error(), slog.Any("error", err))
    81  	}
    82  
    83  	if instruments.ActorStoppedCount, err = meter.Int64Counter(
    84  		"protoactor_actor_stopped_count",
    85  		metric.WithDescription("Number of actors stopped"),
    86  		metric.WithUnit("1"),
    87  	); err != nil {
    88  		err = fmt.Errorf("failed to create ActorStoppedCount instrument, %w", err)
    89  		logger.Error(err.Error(), slog.Any("error", err))
    90  	}
    91  
    92  	if instruments.ActorSpawnCount, err = meter.Int64Counter(
    93  		"protoactor_actor_spawn_count",
    94  		metric.WithDescription("Number of actors spawn"),
    95  		metric.WithUnit("1"),
    96  	); err != nil {
    97  		err = fmt.Errorf("failed to create ActorSpawnCount instrument, %w", err)
    98  		logger.Error(err.Error(), slog.Any("error", err))
    99  	}
   100  
   101  	if instruments.DeadLetterCount, err = meter.Int64Counter(
   102  		"protoactor_deadletter_count",
   103  		metric.WithDescription("Number of deadletters"),
   104  		metric.WithUnit("1"),
   105  	); err != nil {
   106  		err = fmt.Errorf("failed to create DeadLetterCount instrument, %w", err)
   107  		logger.Error(err.Error(), slog.Any("error", err))
   108  	}
   109  
   110  	if instruments.FuturesCompletedCount, err = meter.Int64Counter(
   111  		"protoactor_futures_completed_count",
   112  		metric.WithDescription("Number of futures completed"),
   113  		metric.WithUnit("1"),
   114  	); err != nil {
   115  		err = fmt.Errorf("failed to create FuturesCompletedCount instrument, %w", err)
   116  		logger.Error(err.Error(), slog.Any("error", err))
   117  	}
   118  
   119  	if instruments.FuturesStartedCount, err = meter.Int64Counter(
   120  		"protoactor_futures_started_count",
   121  		metric.WithDescription("Number of futures started"),
   122  		metric.WithUnit("1"),
   123  	); err != nil {
   124  		err = fmt.Errorf("failed to create FuturesStartedCount instrument, %w", err)
   125  		logger.Error(err.Error(), slog.Any("error", err))
   126  	}
   127  
   128  	if instruments.FuturesTimedOutCount, err = meter.Int64Counter(
   129  		"protoactor_futures_timed_out_count",
   130  		metric.WithDescription("Number of futures timed out"),
   131  		metric.WithUnit("1"),
   132  	); err != nil {
   133  		err = fmt.Errorf("failed to create FuturesTimedOutCount instrument, %w", err)
   134  		logger.Error(err.Error(), slog.Any("error", err))
   135  	}
   136  
   137  	if instruments.ThreadPoolLatency, err = meter.Int64Histogram(
   138  		"protoactor_thread_pool_latency_duration_seconds",
   139  		metric.WithDescription("History of latency in second"),
   140  		metric.WithUnit("ms"),
   141  	); err != nil {
   142  		err = fmt.Errorf("failed to create ThreadPoolLatency instrument, %w", err)
   143  		logger.Error(err.Error(), slog.Any("error", err))
   144  	}
   145  
   146  	return &instruments
   147  }
   148  
   149  // SetActorMailboxLengthGauge makes sure access to ActorMailboxLength is sequenced
   150  func (am *ActorMetrics) SetActorMailboxLengthGauge(gauge metric.Int64ObservableGauge) {
   151  	// lock our mutex
   152  	am.mu.Lock()
   153  	defer am.mu.Unlock()
   154  
   155  	am.ActorMailboxLength = gauge
   156  }