monitor

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 26, 2026 License: MIT Imports: 19 Imported by: 0

README

Monitor SDK

A lightweight, high-performance metrics collection SDK for Go applications with Prometheus Remote Write support.

Features

  • Multiple metric types: Counters, Gauges, Histograms with labeled variants
  • Thread-safe design: Built with atomic operations and minimal locking
  • Memory bounded: TTL and max-series limits prevent unbounded growth
  • Prometheus compatible: Standard __name__, job, instance labels
  • Advanced DNS: Custom resolvers (UDP, DoT, DoH) with caching and failover
  • System metrics: Built-in collectors for memory, GC, and goroutine stats

Installation

go get github.com/nikiz24/monitor

Quick Start

package main

import (
    "log"
    "time"
    
    "github.com/nikiz24/monitor"
    "go.uber.org/zap"
)

func main() {
    logger, _ := zap.NewProduction()
    defer logger.Sync()

    config := monitor.Config{
        Namespace:           "myapp",
        Subsystem:           "prod",
        ServiceName:         "my_service",
        RemoteWriteURL:      "http://prometheus:9090/api/v1/write",
        RemoteWriteInterval: 15 * time.Second,
        Logger:              logger,
    }

    if err := monitor.Init(config); err != nil {
        log.Fatal("Failed to initialize monitoring:", err)
    }
    defer monitor.Shutdown()
    
    // Register system metrics
    monitor.RegisterSystemMetricsCollector(logger)
    
    // Use metrics
    monitor.IncrementCounter("requests_total")
    monitor.SetLabeledCounter("connections", 42, "type", "websocket")
    monitor.ObserveHistogram("response_time_us", 123.45)
}

Basic Usage

Counters
// Simple counters
monitor.IncrementCounter("requests_total")
monitor.AddCounter("bytes_processed", 1024)
monitor.SetCounter("active_connections", 42)

// Get current value
count := monitor.GetCounter("requests_total")
Labeled Counters
// Increment with labels
monitor.IncrementLabeledCounter("http_requests", 
    "method", "GET", 
    "endpoint", "/api/users", 
    "status", "200")

// Set specific value
monitor.SetLabeledCounter("connected_users", 5, 
    "region", "us-west", 
    "type", "premium")

// Delete specific series
monitor.DeleteLabeledCounter("http_requests", 
    "method", "GET", 
    "endpoint", "/api/users")
Histograms
// Register custom buckets (optional)
monitor.RegisterHistogramBuckets("response_time", []float64{
    10, 20, 50, 100, 200, 500, 1000, 2000, 5000,
})

// Record observations
monitor.ObserveHistogram("response_time", 156.7)

Advanced Configuration

DNS Resolvers

For environments with custom DNS requirements:

config := monitor.Config{
    // ... basic config ...
    
    // Enable advanced DNS resolution
    DNSEnable:          true,
    DNSCacheTTL:        10 * time.Minute,
    DNSRefreshInterval: 5 * time.Minute,
    DNSTimeout:         800 * time.Millisecond,
    
    // Custom resolvers (optional)
    DNSUDPServers:   []string{"1.1.1.1:53", "8.8.8.8:53"},
    DNSTLSServers:   []string{"1.1.1.1:853", "9.9.9.9:853"},
    DNSDoHEndpoints: []string{"https://cloudflare-dns.com/dns-query"},
}
Custom Collectors
type MyCollector struct {
    monitor.BaseCollector
}

func NewMyCollector(logger *zap.Logger) *MyCollector {
    return &MyCollector{
        BaseCollector: monitor.NewBaseCollector("my_collector", logger),
    }
}

func (c *MyCollector) Collect() []monitor.Metric {
    return []monitor.Metric{
        {
            Name:       "custom_metric",
            Value:      123.4,
            Labels:     map[string]string{"label1": "value1"},
            MetricType: monitor.Gauge,
            Timestamp:  time.Now(),
        },
    }
}

// Register the collector
collector := NewMyCollector(logger)
monitor.RegisterCollector(collector)
Application-Specific Collectors
// Create a labeled counter collector for your application
appCollector := monitor.NewApplicationCollector("http_requests", logger)

// Configure memory limits
appCollector.SetTTL(30 * time.Minute)    // Clean up after 30 minutes
appCollector.SetMaxSeries(50000)         // Limit to 50k time series

// Use it
appCollector.Inc("total", "method", "GET", "endpoint", "/api/users")
appCollector.Set("active", 42, "region", "us-west")

System Metrics

The SDK includes built-in system metrics collection:

// Register system metrics collector
monitor.RegisterSystemMetricsCollector(logger)

// Available metrics:
// - memory_alloc_bytes
// - memory_sys_bytes  
// - memory_heap_alloc_bytes
// - memory_heap_inuse_bytes
// - goroutines_total
// - gc_runs_total

// Get detailed GC stats
gcStats := monitor.ReadGCStats()
logger.Info("GC statistics",
    zap.Time("last_gc", gcStats.LastGC),
    zap.Int64("num_gc", gcStats.NumGC),
    zap.Duration("pause_total", gcStats.PauseTotal))

// Get memory usage
alloc, sys, heapInUse := monitor.GetProcessMemory()

// Trigger GC manually
monitor.TriggerGC()

Prometheus Integration

Metrics are automatically formatted for Prometheus with:

  • Metric naming: {namespace}_{subsystem}_{metric_name}
  • Standard labels: __name__, _instance_, instance, _target_
  • Custom labels: Added from Config.CustomLabels
  • Metric labels: Added from individual metric calls

Example output:

myapp_prod_requests_total{__name__="myapp_prod_requests_total",_instance_="10.0.1.5",instance="10.0.1.5",_target_="my_service",method="GET",endpoint="/api/users"} 42

Memory Management

Labeled counters support automatic cleanup to prevent memory leaks:

collector := monitor.NewApplicationCollector("metrics", logger)

// Set TTL - series not updated within this time are removed
collector.SetTTL(60 * time.Minute)

// Set max series - oldest series are evicted when limit is exceeded  
collector.SetMaxSeries(100000)

Best Practices

  1. Initialize early: Set up monitoring at application startup
  2. Control cardinality: Limit high-cardinality labels and use TTL/max-series
  3. Reasonable intervals: Use 15-30 second write intervals
  4. Proper shutdown: Always call monitor.Shutdown() on exit
  5. Monitor the monitor: Watch for memory usage and performance impact

Health Monitoring and Management

The SDK provides built-in health check and management functions:

Health Check
// Check if monitoring system is healthy
if err := monitor.HealthCheck(); err != nil {
    log.Printf("Monitor health check failed: %v", err)
}

// Get detailed system status
status := monitor.GetStatus()
log.Printf("Monitor status: %+v", status)
Connection Management
// Refresh DNS and recreate connections (useful for network changes)
if err := monitor.RefreshConnection(); err != nil {
    log.Printf("Connection refresh failed: %v", err)
}

// Force immediate metric write (useful for testing connectivity)
if err := monitor.ForceWrite(); err != nil {
    log.Printf("Force write failed: %v", err)
}
Periodic Health Checks
// Example: Periodic health monitoring
go func() {
    ticker := time.NewTicker(10 * time.Minute)
    defer ticker.Stop()
    
    for range ticker.C {
        if err := monitor.HealthCheck(); err != nil {
            logger.Error("Monitor unhealthy", zap.Error(err))
            continue
        }
        
        // Refresh connection for DNS changes
        monitor.RefreshConnection()
        
        // Test connectivity
        monitor.SetCounter("heartbeat", time.Now().Unix())
        if err := monitor.ForceWrite(); err != nil {
            logger.Error("Connectivity test failed", zap.Error(err))
        }
    }
}()

Error Handling

The SDK is designed to be resilient:

  • Failed remote writes are logged but don't crash the application
  • DNS failures trigger automatic resolver failover and retry
  • Memory limits prevent unbounded growth from high-cardinality metrics
  • Thread-safe operations prevent data races
  • Health check functions help detect and recover from issues

License

MIT License - see LICENSE file for details.

Documentation

Overview

Package monitor provides a lightweight, high-performance metrics collection SDK for Go applications with Prometheus Remote Write support.

Design goals:

  • Minimal overhead and allocations for hot paths
  • Thread-safe primitives built with atomic operations
  • Bounded memory with TTL and max-series limits for labeled counters
  • Prometheus-compatible format with standard labels

Basic usage:

config := monitor.Config{
  Namespace:           "myapp",
  Subsystem:           "prod",
  ServiceName:         "service",
  RemoteWriteURL:      "http://prometheus:9090/api/v1/write",
  RemoteWriteInterval: 15 * time.Second,
}

if err := monitor.Init(config); err != nil {
  log.Fatal(err)
}
defer monitor.Shutdown()

monitor.IncrementCounter("requests_total")
monitor.SetLabeledCounter("connections", 42, "type", "websocket")
monitor.ObserveHistogram("response_time", 0.123)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddCounter

func AddCounter(name string, delta int64)

AddCounter adds a specific value to a counter

func DecrementCounter

func DecrementCounter(name string)

DecrementCounter decrements a counter by 1

func DecrementLabeledCounter

func DecrementLabeledCounter(name string, labels ...string)

DecrementLabeledCounter decrements a labeled counter

func DeleteLabeledCounter

func DeleteLabeledCounter(name string, labels ...string)

DeleteLabeledCounter deletes a specific labeled counter

func ForceWrite

func ForceWrite() error

ForceWrite immediately writes all current metrics to the remote endpoint This is useful for health checks and testing

func GetCounter

func GetCounter(name string) int64

GetCounter gets the current value of a counter

func GetLabeledCounter

func GetLabeledCounter(name string, labels ...string) int64

GetLabeledCounter gets the current value of a labeled counter

func GetOutboundIPv4

func GetOutboundIPv4() (string, error)

GetOutboundIPv4 gets the outbound IPv4 address of the local machine

func GetProcessMemory

func GetProcessMemory() (alloc, sys, heapInUse uint64)

GetProcessMemory returns current process memory usage

func GetStatus

func GetStatus() map[string]interface{}

GetStatus returns the current status of the monitoring system

func HealthCheck

func HealthCheck() error

HealthCheck performs a health check on the monitoring system

func IncrementCounter

func IncrementCounter(name string)

IncrementCounter increments a counter by 1

func IncrementLabeledCounter

func IncrementLabeledCounter(name string, labels ...string)

IncrementLabeledCounter increments a labeled counter labels should be provided as [key1, value1, key2, value2, ...]

func Init

func Init(config Config) error

Init initializes the global monitoring system

func ObserveHistogram

func ObserveHistogram(name string, value float64)

ObserveHistogram records a value in a histogram

func RefreshConnection

func RefreshConnection() error

RefreshConnection attempts to refresh the remote write connection This is useful for DNS changes or network connectivity issues

func RegisterCollector

func RegisterCollector(collector Collector) error

RegisterCollector registers a custom metrics collector

func RegisterHistogramBuckets

func RegisterHistogramBuckets(name string, buckets []float64)

RegisterHistogramBuckets registers custom histogram buckets

func RegisterSystemMetricsCollector

func RegisterSystemMetricsCollector(logger *zap.Logger) error

RegisterSystemMetricsCollector registers the system metrics collector with the global monitor

func SetCounter

func SetCounter(name string, value int64)

SetCounter sets a counter to a specific value

func SetLabeledCounter

func SetLabeledCounter(name string, value float64, labels ...string)

SetLabeledCounter sets a labeled counter to a specific value

func Shutdown

func Shutdown()

Shutdown shuts down the global monitoring system

func TriggerGC

func TriggerGC()

TriggerGC triggers garbage collection

Types

type BaseCollector

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

BaseCollector provides basic collector functionality

func NewBaseCollector

func NewBaseCollector(name string, logger *zap.Logger) BaseCollector

NewBaseCollector creates a base collector

func (*BaseCollector) Name

func (b *BaseCollector) Name() string

Name implements Collector interface

type Collector

type Collector interface {
	Collect() []Metric
	Name() string
}

Collector defines a metrics collector that can provide multiple metrics

type Config

type Config struct {
	// Service identification
	Namespace   string
	Subsystem   string
	ServiceName string

	// Remote write configuration
	RemoteWriteURL      string
	RemoteWriteInterval time.Duration

	// Instance information
	InstanceIP   string
	Version      string
	BuildCommit  string
	BuildTime    string
	CustomLabels map[string]string

	// Optional logger
	Logger *zap.Logger

	// DNS resolver options (optional, for advanced use cases)
	DNSEnable          bool
	DNSCacheTTL        time.Duration
	DNSRefreshInterval time.Duration
	DNSTimeout         time.Duration
	DNSUDPServers      []string // e.g. ["1.1.1.1:53", "8.8.8.8:53"]
	DNSTLSServers      []string // e.g. ["1.1.1.1:853", "9.9.9.9:853"]
	DNSDoHEndpoints    []string // e.g. ["https://cloudflare-dns.com/dns-query"]
}

Config defines the configuration for the metrics system

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a default configuration

type CounterCollector

type CounterCollector struct {
	BaseCollector
	// contains filtered or unexported fields
}

CounterCollector provides simple counter metrics

func NewCounterCollector

func NewCounterCollector(name string, logger *zap.Logger) *CounterCollector

NewCounterCollector creates a new counter collector

func (*CounterCollector) Add

func (c *CounterCollector) Add(name string, delta int64)

Add adds a specific value to a counter

func (*CounterCollector) Collect

func (c *CounterCollector) Collect() []Metric

Collect implements Collector interface

func (*CounterCollector) Get

func (c *CounterCollector) Get(name string) int64

Get gets the current value of a counter

func (*CounterCollector) Inc

func (c *CounterCollector) Inc(name string)

Inc increments a counter by 1

func (*CounterCollector) Set

func (c *CounterCollector) Set(name string, value int64)

Set sets a counter to a specific value (makes it a gauge)

type GCStats

type GCStats struct {
	LastGC     time.Time
	NumGC      int64
	PauseTotal time.Duration
}

GCStats represents garbage collection statistics

func ReadGCStats

func ReadGCStats() GCStats

ReadGCStats reads garbage collection statistics

type HistogramCollector

type HistogramCollector struct {
	BaseCollector
	// contains filtered or unexported fields
}

HistogramCollector provides histogram metrics

func NewHistogramCollector

func NewHistogramCollector(name string, logger *zap.Logger) *HistogramCollector

NewHistogramCollector creates a new histogram collector

func (*HistogramCollector) Collect

func (h *HistogramCollector) Collect() []Metric

Collect implements Collector interface

func (*HistogramCollector) Observe

func (h *HistogramCollector) Observe(name string, value float64)

Observe records a value in a histogram

func (*HistogramCollector) RegisterHistogram

func (h *HistogramCollector) RegisterHistogram(name string, buckets []float64)

RegisterHistogram registers a histogram with specified buckets

type LabeledCounterCollector

type LabeledCounterCollector struct {
	BaseCollector
	// contains filtered or unexported fields
}

LabeledCounterCollector provides labeled counter metrics

func NewApplicationCollector

func NewApplicationCollector(name string, logger *zap.Logger) *LabeledCounterCollector

NewApplicationCollector creates an application-specific collector

func NewLabeledCounterCollector

func NewLabeledCounterCollector(name string, logger *zap.Logger) *LabeledCounterCollector

NewLabeledCounterCollector creates a new labeled counter collector

func (*LabeledCounterCollector) Collect

func (c *LabeledCounterCollector) Collect() []Metric

Collect implements Collector interface

func (*LabeledCounterCollector) Dec

func (c *LabeledCounterCollector) Dec(metricName string, labels ...string)

Dec decrements a labeled counter

func (*LabeledCounterCollector) Delete

func (c *LabeledCounterCollector) Delete(metricName string, labels ...string)

Delete removes a specific labeled counter entry

func (*LabeledCounterCollector) ForceCleanup

func (c *LabeledCounterCollector) ForceCleanup()

ForceCleanup forces immediate cleanup regardless of time intervals

func (*LabeledCounterCollector) Get

func (c *LabeledCounterCollector) Get(metricName string, labels ...string) int64

Get gets the current value of a labeled counter

func (*LabeledCounterCollector) Inc

func (c *LabeledCounterCollector) Inc(metricName string, labels ...string)

Inc increments a labeled counter

func (*LabeledCounterCollector) Set

func (c *LabeledCounterCollector) Set(metricName string, value float64, labels ...string)

Set sets a labeled counter to a specific value

func (*LabeledCounterCollector) SetMaxSeries

func (c *LabeledCounterCollector) SetMaxSeries(n int)

SetMaxSeries sets the maximum number of time series (0 means no limit)

func (*LabeledCounterCollector) SetTTL

func (c *LabeledCounterCollector) SetTTL(ttl time.Duration)

SetTTL sets the TTL for time series

type Manager

type Manager interface {
	Start() error
	Stop()
	RegisterCollector(collector Collector)
	GetMetrics() []Metric
}

Manager is the main interface for metrics collection and reporting

func NewManager

func NewManager(config Config) (Manager, error)

NewManager creates a new metrics manager

type Metric

type Metric struct {
	Name       string
	Value      float64
	Labels     map[string]string
	MetricType MetricType
	Timestamp  time.Time
}

Metric represents a single metric data point

type MetricType

type MetricType int

MetricType represents the type of a metric

const (
	Counter MetricType = iota
	Gauge
	Histogram
	Summary
)

type SystemMetricsCollector

type SystemMetricsCollector struct {
	BaseCollector
}

SystemMetricsCollector collects basic system metrics

func NewSystemMetricsCollector

func NewSystemMetricsCollector(logger *zap.Logger) *SystemMetricsCollector

NewSystemMetricsCollector creates a new system metrics collector

func (*SystemMetricsCollector) Collect

func (s *SystemMetricsCollector) Collect() []Metric

Collect implements Collector interface

Jump to

Keyboard shortcuts

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