metrics

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 14, 2025 License: Apache-2.0 Imports: 12 Imported by: 2

README

Logging SDK latency metrics and other custom metrics

Go Reference

AWS SDK Go v2 middleware to measure and emit latency and fault metrics on the AWS requests. Additionally, you can also emit custom metrics in JSON format which can then be parsed in CloudWatch Logs or turned into CloudWatch metrics.

Usage

Get with:

go get github.com/nguyengg/go-aws-commons/metrics
package main

import (
	"context"

	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/dynamodb"
	"github.com/nguyengg/go-aws-commons/metrics"
	"github.com/rs/zerolog"
)

func main() {
	// this will attach a middleware that logs all AWS calls for latency.
	cfg, _ := config.LoadDefaultConfig(context.Background(), metrics.WithClientSideMetrics())

	// just use the cfg to create the AWS clients normally, for example with DynamoDB:
	_ = dynamodb.NewFromConfig(cfg)

	// in your handler, before making the AWS calls, you must attach a metrics instance to the context that will be
	// passed to the clients.
	ctx := metrics.WithContext(context.Background(), metrics.New())

	// you can use the metrics instance to add more metrics.
	m := metrics.Ctx(ctx).AddCount("userDidSomething", 1)

	// then, at the end of the request, print the metrics.
	m.Log(zerolog.Ctx(ctx))

	// here's a real log message from my production website.
	/**
	{
	    "startTime": 1739504515510,
	    "endTime": "Fri, 14 Feb 2025 03:41:57 GMT",
	    "time": "1602.040 ms",
	    "statusCode": 200,
	    "requestId": "0401b979-2355-4413-a4e8-ea8e6c798491",
	    "path": "/api/payments/issaquah/2025/02/13",
	    "method": "GET",
	    "sessionIdHash": "03eb5405e8cc3926",
	    "user.sub": "50407e6f-f34d-4762-9070-2bc26a011fc5",
	    "site": "issaquah",
	    "counters": {
	        "fault": 0,
	        "sessionCacheHit": 0,
	        "isAuthenticated": 1,
	        "availableFromS3": 0,
	        "S3.GetObject.ServerFault": 0,
	        "S3.GetObject.UnknownFault": 0,
	        "DynamoDB.Query.ClientFault": 0,
	        "DynamoDB.Query.ServerFault": 0,
	        "panicked": 0,
	        "S3.GetObject.ClientFault": 0,
	        "DynamoDB.Query.UnknownFault": 0,
	        "2xx": 1,
	        "4xx": 0,
	        "5xx": 0
	    },
	    "timings": {
	        "S3.GetObject": {
	            "sum": "64.680 ms",
	            "min": "64.680 ms",
	            "max": "64.680 ms",
	            "n": 1,
	            "avg": "64.680 ms"
	        },
	        "DynamoDB.Query": {
	            "sum": "74.255 ms",
	            "min": "74.255 ms",
	            "max": "74.255 ms",
	            "n": 1,
	            "avg": "74.255 ms"
	        }
	    }
	}
	*/
}

Documentation

Index

Constants

View Source
const (
	CounterKeyFault    = "fault"
	CounterKeyPanicked = "panicked"
)

WithClientSideMetrics counter metrics that are always emitted.

View Source
const (
	ReservedKeyStartTime = "startTime"
	ReservedKeyEndTime   = "endTime"
	ReservedKeyTime      = "time"
	ReservedKeyCounters  = "counters"
	ReservedKeyFloaters  = "floaters"
	ReservedKeyTimings   = "timings"
)

Reserved property keys.

View Source
const (
	StatusCode1xx = 1 << iota
	StatusCode2xx
	StatusCode3xx
	StatusCode4xx
	StatusCode5xx
	StatusCodeCommon = StatusCode2xx | StatusCode4xx | StatusCode5xx
	StatusCodeAll    = StatusCode1xx | StatusCode2xx | StatusCode3xx | StatusCode4xx | StatusCode5xx
)

Variables

This section is empty.

Functions

func ClientSideMetricsMiddleware

func ClientSideMetricsMiddleware(options ...Option) func(stack *smithymw.Stack) error

ClientSideMetricsMiddleware creates a new middleware to add client-side latency metrics about the requests.

Usage:

cfg, _ := config.LoadDefaultConfig(ctx)
cfg.APIOptions = append(cfg.APIOptions, metrics.ClientSideMetricsMiddleware())

A metrics.Metrics instance must be available from context by the time the middleware receives a response. By default, zerolog.Ctx is used to retrieve a zerolog.Logger instance that logs the metrics instance. This can be customised via WithLogger.

func FormatDuration

func FormatDuration(duration time.Duration) string

FormatDuration formats the duration in layout 12.345ms.

func WithClientSideMetrics

func WithClientSideMetrics(options ...Option) func(*config.LoadOptions) error

WithClientSideMetrics adds a ClientSideMetricsMiddleware to the config.

Usage:

cfg, err := config.LoadDefaultConfig(context.TODO(), metrics.WithClientSideMetrics())

func WithContext

func WithContext(ctx context.Context, m Metrics) context.Context

WithContext returns a new child context with the given metrics attached.

The metrics can be retrieved using Ctx(child) or TryCtx(child).

Types

type Metrics

type Metrics interface {
	// SetProperty creates or modifies a string key-value property pair.
	//
	// Properties are top-level fields in the JSON log message. A few properties are generated by the metrics instance
	// and cannot be overridden:
	//   - startTime: epoch millisecond for machine parsing
	//   - endTime: http.TimeFormat for human readability
	//   - time: latency from metrics' creation to when it's logged - in milliseconds
	//   - timings: generic latencies - in milliseconds
	//   - counters (int64) and floaters (float64)
	//
	// If called multiples on the same key, the last one wins.
	//
	// Returns self for chaining.
	SetProperty(key, value string) Metrics
	// SetInt64Property is a variant of SetProperty for int64 values.
	SetInt64Property(key string, value int64) Metrics
	// SetFloat64Property is a variant of SetProperty for float64 values.
	SetFloat64Property(key string, value float64) Metrics
	// SetJSONProperty is a variant of SetProperty for values that don't fit the other variants.
	// If the value fails to be serialised, the error message will be used in its stead.
	// See zerolog.Event's Interface method.
	SetJSONProperty(key string, v interface{}) Metrics
	// SetCount sets the integer counter of the specified key to a value.
	// Additional names can be given to ensure they exist with the initial value (0) unless they've already been set.
	// Returns self for chaining.
	SetCount(key string, value int64, ensureExist ...string) Metrics

	// AddCount increases the integer counter of the specified key by a delta.
	// Additional names can be given to ensure they exist with the initial value (0) unless they've already been set.
	// Use IncrementCount if you need to increase by 1.
	// Returns self for chaining.
	AddCount(key string, delta int64, ensureExist ...string) Metrics
	// IncrementCount is a convenient method to increase the integer counter of the specified key by 1.
	// Returns self for chaining.
	IncrementCount(key string) Metrics
	// Faulted is a convenient method to increase the integer counter named CounterKeyFault by 1.
	// Returns self for chaining.
	Faulted() Metrics
	// Panicked is a convenient method to increase the integer counter named CounterKeyPanicked by 1.
	// Returns self for chaining.
	Panicked() Metrics

	// SetFloat sets the float counter of the specified key to a value.
	// Additional names can be given to ensure they exist with the initial value (0) unless they've already been set.
	// Returns self for chaining.
	SetFloat(key string, value float64, ensureExist ...string) Metrics
	// AddFloat increases the float counter of the specified key by a delta.
	// Additional names can be given to ensure they exist with the initial value (0) unless they've already been set.
	// Returns self for chaining.
	AddFloat(key string, delta float64, ensureExist ...string) Metrics

	// SetTiming sets a timing metric of the specified key to a duration.
	// Returns self for chaining.
	SetTiming(key string, duration time.Duration) Metrics
	// AddTiming increases a timing metric of the specified key by a delta.
	// Returns self for chaining.
	AddTiming(key string, delta time.Duration) Metrics

	// SetStatusCode sets a "statusCode" property and start additional status code counters (StatusCodeCommon).
	// Use SetStatusCodeWithFlags to customise which status code counter is not printed.
	// Returns self for chaining.
	SetStatusCode(statusCode int) Metrics
	// SetStatusCodeWithFlag emits a "statusCode" property and additional counters controlled by flag.
	// If flag is 0, only the yxx counter matching the given status code is set to 1. Otherwise, whichever
	// status code flag is specified (StatusCode1xx, StatusCode3xx, StatusCodeCommon, StatusCodeAll, etc.) get a
	// 0-value metric.
	// Returns self for chaining.
	SetStatusCodeWithFlag(statusCode int, flag int) Metrics

	// Log uses the given logger to write the metrics contents.
	Log(*zerolog.Logger)
	// LogWithEndTime is a variant of Log that receives an explicit end time.
	LogWithEndTime(*zerolog.Logger, time.Time)
}

Metrics contains metrics that can be logged as structured JSON using zerolog.

func Ctx

func Ctx(ctx context.Context) Metrics

Ctx returns the Metrics instance from the specified context if available.

If not, a NullMetrics instance will be used.

func New

func New() Metrics

New creates an empty SimpleMetrics instance. The current UTC time will be the startTime property.

func NewWithStartTime

func NewWithStartTime(startTime time.Time) Metrics

NewWithStartTime is a variant of New that allows caller to override the startTime property.

func TryCtx

func TryCtx(ctx context.Context) (Metrics, bool)

TryCtx is a variant of Ctx that does not return NullMetrics.

Use this if you absolutely need an existing Metrics instance to exist.

type NullMetrics

type NullMetrics struct {
}

NullMetrics no-ops on all implementations.

func (*NullMetrics) AddCount

func (m *NullMetrics) AddCount(string, int64, ...string) Metrics

func (*NullMetrics) AddFloat

func (m *NullMetrics) AddFloat(string, float64, ...string) Metrics

func (*NullMetrics) AddTiming

func (m *NullMetrics) AddTiming(string, time.Duration) Metrics

func (*NullMetrics) Faulted

func (m *NullMetrics) Faulted() Metrics

func (*NullMetrics) IncrementCount

func (m *NullMetrics) IncrementCount(string) Metrics

func (*NullMetrics) Log

func (m *NullMetrics) Log(logger *zerolog.Logger)

func (*NullMetrics) LogWithEndTime

func (m *NullMetrics) LogWithEndTime(logger *zerolog.Logger, _ time.Time)

func (*NullMetrics) Panicked

func (m *NullMetrics) Panicked() Metrics

func (*NullMetrics) SetCount

func (m *NullMetrics) SetCount(string, int64, ...string) Metrics

func (*NullMetrics) SetFloat

func (m *NullMetrics) SetFloat(string, float64, ...string) Metrics

func (*NullMetrics) SetFloat64Property

func (m *NullMetrics) SetFloat64Property(string, float64) Metrics

func (*NullMetrics) SetInt64Property

func (m *NullMetrics) SetInt64Property(string, int64) Metrics

func (*NullMetrics) SetJSONProperty

func (m *NullMetrics) SetJSONProperty(string, interface{}) Metrics

func (*NullMetrics) SetProperty

func (m *NullMetrics) SetProperty(string, string) Metrics

func (*NullMetrics) SetStatusCode

func (m *NullMetrics) SetStatusCode(int) Metrics

func (*NullMetrics) SetStatusCodeWithFlag

func (m *NullMetrics) SetStatusCodeWithFlag(int, int) Metrics

func (*NullMetrics) SetTiming

func (m *NullMetrics) SetTiming(string, time.Duration) Metrics

type Option

type Option func(*clientSideMetricsMiddleware)

Option allows customization of the ClientSideMetricsMiddleware.

At the moment, there are no customizations available yet.

func WithLogger

func WithLogger(logFn func(context.Context) *zerolog.Logger) Option

WithLogger changes the zerolog.Logger instance that is used.

By default, zerolog.Ctx is used to retrieve the logger from context.

type SimpleMetrics

type SimpleMetrics struct {
	// contains filtered or unexported fields
}

SimpleMetrics is thread-safe by use of mutex.

func (*SimpleMetrics) AddCount

func (m *SimpleMetrics) AddCount(key string, delta int64, ensureExist ...string) Metrics

func (*SimpleMetrics) AddFloat

func (m *SimpleMetrics) AddFloat(key string, delta float64, ensureExist ...string) Metrics

func (*SimpleMetrics) AddTiming

func (m *SimpleMetrics) AddTiming(key string, delta time.Duration) Metrics

func (*SimpleMetrics) Faulted

func (m *SimpleMetrics) Faulted() Metrics

func (*SimpleMetrics) IncrementCount

func (m *SimpleMetrics) IncrementCount(key string) Metrics

func (*SimpleMetrics) Log

func (m *SimpleMetrics) Log(logger *zerolog.Logger)

func (*SimpleMetrics) LogWithEndTime

func (m *SimpleMetrics) LogWithEndTime(logger *zerolog.Logger, endTime time.Time)

func (*SimpleMetrics) Panicked

func (m *SimpleMetrics) Panicked() Metrics

func (*SimpleMetrics) SetCount

func (m *SimpleMetrics) SetCount(key string, value int64, ensureExist ...string) Metrics

func (*SimpleMetrics) SetFloat

func (m *SimpleMetrics) SetFloat(key string, value float64, ensureExist ...string) Metrics

func (*SimpleMetrics) SetFloat64Property

func (m *SimpleMetrics) SetFloat64Property(key string, value float64) Metrics

func (*SimpleMetrics) SetInt64Property

func (m *SimpleMetrics) SetInt64Property(key string, value int64) Metrics

func (*SimpleMetrics) SetJSONProperty

func (m *SimpleMetrics) SetJSONProperty(key string, value interface{}) Metrics

func (*SimpleMetrics) SetProperty

func (m *SimpleMetrics) SetProperty(key, value string) Metrics

func (*SimpleMetrics) SetStatusCode

func (m *SimpleMetrics) SetStatusCode(statusCode int) Metrics

func (*SimpleMetrics) SetStatusCodeWithFlag

func (m *SimpleMetrics) SetStatusCodeWithFlag(statusCode int, flag int) Metrics

func (*SimpleMetrics) SetTiming

func (m *SimpleMetrics) SetTiming(key string, duration time.Duration) Metrics

type TimingStats

type TimingStats struct {
	Sum time.Duration
	Min time.Duration
	Max time.Duration
	N   int64
}

func NewTimingStats

func NewTimingStats(duration time.Duration) TimingStats

func (*TimingStats) Add

func (s *TimingStats) Add(duration time.Duration) *TimingStats

func (*TimingStats) Avg

func (s *TimingStats) Avg() time.Duration

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL