monitoring

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 14, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

README

Monitoring System for Seshat

A comprehensive monitoring and observability system for Seshat providing metrics, logging, and instrumentation.

Components

1. Metrics System

Provides structured metrics collection with multiple metric types:

Counters

Monotonically increasing metrics for event counting:

counter := monitoring.NewCounter("api_requests_total", map[string]string{
    "subsystem": "api",
    "type":      "requests",
})
counter.Inc()
counter.Add(5)
Gauges

Point-in-time metrics for current state:

gauge := monitoring.NewGauge("active_sessions", map[string]string{
    "subsystem": "system",
    "type":      "sessions",
})
gauge.Set(42.5)
gauge.Add(10.0)
Timers

Duration metrics with percentile calculations:

timer := monitoring.NewTimer("api_latency_ms", map[string]string{
    "subsystem": "api",
    "type":      "latency",
})
timer.Record(150 * time.Millisecond)

// Or using Start/Stop pattern
stop := timer.Start()
// ... perform operation
stop()
Histograms

Value distribution metrics:

histogram := monitoring.NewHistogram("request_duration_ms", labels, []float64{
    1, 5, 10, 25, 50, 100, 250, 500, 1000,
})
histogram.Observe(42.5)
2. Logging System

Structured logging with context awareness:

logger := monitoring.NewLoggerWithConfig(&monitoring.LoggerConfig{
    Level:         monitoring.LogLevelInfo,
    Output:        "stdout",
    Format:        "text",
    ContextFields: []string{"session_id", "turn_id"},
})

// Simple logging
logger.Info("Message", nil)

// Context-aware logging
ctx := context.Background()
logger.InfoWithContext(ctx, "Contextual message", nil)

// Logging with fields
logger.ErrorWithStack("Error occurred", err, map[string]interface{}{
    "operation": "api_call",
    "user_id":   "user-123",
})
3. Monitoring System

Centralized monitoring that aggregates all subsystem metrics:

monitoringSystem := monitoring.NewSystem(logger)

// Record API metrics
monitoringSystem.RecordAPIRequest()
monitoringSystem.RecordAPISuccess(duration)
monitoringSystem.RecordAPIFailure(err, duration)

// Record tool metrics
monitoringSystem.RecordToolCall("file_read")
monitoringSystem.RecordToolSuccess("file_read", duration)
monitoringSystem.RecordToolFailure("file_read", err, duration)

// Record query metrics
monitoringSystem.RecordQueryTurn()
monitoringSystem.RecordQuerySuccess(duration)
monitoringSystem.RecordQueryFailure(err, duration)

// Get all metrics
metrics := monitoringSystem.GetAllMetrics()

// Export metrics
snapshot, _ := monitoringSystem.GetMetricsSnapshot("prometheus")
fmt.Println(snapshot)

Metric Types Available

API Metrics
  • api_requests_total - Total API requests
  • api_requests_success - Successful API requests
  • api_requests_failure - Failed API requests
  • api_latency_ms - API request latency (with percentiles)
  • api_rate_limit_hits - Rate limit events
  • api_circuit_breaker_trips - Circuit breaker activations
Tool Metrics
  • tool_calls_total - Total tool calls
  • tool_calls_success - Successful tool calls
  • tool_calls_failure - Failed tool calls
  • tool_latency_ms - Tool execution latency
  • tool_permission_denials - Permission denial events
Query Loop Metrics
  • query_turns_total - Total query turns
  • query_iterations_total - Total query loop iterations
  • query_latency_ms - Query turn latency
  • query_errors - Query errors
Circuit Breaker Metrics
  • circuit_breaker_state_transitions - State change events
  • circuit_breaker_current_state - Current state (0=closed, 1=open, 2=half-open)
System Metrics
  • active_sessions - Currently active sessions
  • active_connections - Active network connections
  • memory_usage_mb - Memory usage in MB
  • total_errors - Total error count

Configuration

Logger Configuration
type LoggerConfig struct {
    Level         LogLevel           // Minimum log level
    Output        string             // stdout, stderr, or file
    FilePath     string             // File path when Output="file"
    Format        string             // text or json
    ContextFields []string           // Context fields to extract
}
Metric Configuration

Metrics can have custom labels for filtering and grouping:

labels := map[string]string{
    "subsystem": "api",
    "provider":  "anthropic",
    "model":      "claude-3-5-sonnet",
}

Testing

Run Tests
# Run all monitoring tests
go test ./internal/monitoring/... -v

# Run specific test suite
go test ./internal/monitoring/metrics_test.go -v
go test ./internal/monitoring/logger_test.go -v
go test ./internal/monitoring/system_test.go -v
Test Coverage
# Generate coverage report
go test ./internal/monitoring/... -coverprofile=coverage.out
go tool cover -html=coverage.html

Integration Examples

1. Basic Setup
import "github.com/EngineerProjects/Nexus_ai/apps/seshat/internal/monitoring"

func main() {
    // Create logger
    logger := monitoring.NewLogger()
    logger.SetLevel(monitoring.LogLevelInfo)

    // Create monitoring system
    monitoringSystem := monitoring.NewSystem(logger)

    // Use monitoring
    monitoringSystem.RecordAPIRequest()
    // ... operation ...
    monitoringSystem.RecordAPISuccess(duration)
}
2. Advanced Setup with Context
func handleRequest(ctx context.Context, request Request) error {
    // Record request start
    monitoringSystem.RecordAPIRequest()

    start := time.Now()

    // Handle request
    err := processRequest(ctx, request)

    duration := time.Since(start)

    if err != nil {
        monitoringSystem.RecordAPIFailure(err, duration)
        logger.LogErrorWithContext(ctx, err, "process_request")
        return err
    }

    monitoringSystem.RecordAPISuccess(duration)
    logger.InfoWithContext(ctx, "Request completed", nil)
    return nil
}
3. Custom Metrics
func setupCustomMetrics(monitoringSystem *monitoring.System) {
    // Create custom counter
    customCounter := monitoring.NewCounter("custom_events", map[string]string{
        "category": "business",
        "type":      "events",
    })

    // Register custom metric
    monitoringSystem.RegisterCustomMetric("custom_events", customCounter)

    // Use custom metric
    customCounter.Inc()
}

Performance Characteristics

Memory Usage
  • Counter: ~48 bytes per instance
  • Gauge: ~56 bytes per instance
  • Timer: ~128 bytes per instance + bucket storage
  • Histogram: ~200 bytes + bucket storage
  • Logger: ~4KB default buffer
  • System: ~10KB base + metrics storage
CPU Usage
  • Counter operations: ~10ns per increment
  • Gauge operations: ~15ns per set
  • Timer operations: ~50-100ns per record
  • Logger operations: ~100-500ns per log entry
  • System queries: ~1-2µs for GetAllMetrics()
Thread Safety

All metric types are thread-safe using mutexes:

  • Counters: Atomic operations where possible
  • Gauges: Full mutex protection
  • Timers: Mutex for histogram operations
  • System: RWMutex for metrics map access

Best Practices

1. Label Strategy

Use consistent, meaningful labels:

// Good
labels := map[string]string{
    "subsystem": "api",
    "provider":  "anthropic",
    "model":      "claude-3-5-sonnet",
}

// Bad - too specific
labels := map[string]string{
    "request_id": "req-12345",
    "timestamp":   "2023-11-15T10:30:00Z",
}

// Bad - too generic
labels := map[string]string{
    "env": "production",
    "app": "seshat",
}
2. Metric Granularity

Balance between detail and cardinality:

// Good - reasonable cardinality
metric := NewTimer("api_latency_ms", map[string]string{
    "subsystem": "api",
    "endpoint":  "/v1/messages", // Low cardinality
})

// Bad - high cardinality (many unique values)
metric := NewTimer("api_latency_ms", map[string]string{
    "subsystem": "api",
    "user_id":   "{user_id}", // Very high cardinality
})
3. Log Level Strategy

Use appropriate log levels:

  • Debug: Detailed development information
  • Info: Normal operational information
  • Warn: Warning conditions that don't stop operation
  • Error: Error conditions that affect operation
  • Fatal: Fatal errors that require immediate termination
4. Context Propagation

Always propagate context for distributed tracing:

func handleRequest(ctx context.Context) {
    // Add request ID to context
    requestID := generateRequestID()
    ctx = context.WithValue(ctx, "request_id", requestID)

    // All operations use context
    processRequest(ctx)
    logRequest(ctx, requestID)
}

Troubleshooting

Metrics Not Updating

Problem: Metrics show zero values

Solutions:

  1. Verify monitoring system is initialized
  2. Check that Record* methods are being called
  3. Ensure no error suppression in metric code
  4. Review log output for initialization errors
High Memory Usage

Problem: Memory grows continuously

Solutions:

  1. Review histogram bucket configurations
  2. Check for metric leaks (unbounded growth)
  3. Implement metric sampling for high-cardinality metrics
  4. Consider metric expiration policies
Poor Performance

Problem: Monitoring overhead is high

Solutions:

  1. Reduce log verbosity
  2. Sample high-frequency metrics
  3. Use appropriate metric types (counter vs timer)
  4. Optimize metric recording frequency

File Structure

internal/monitoring/
├── metrics.go           # Core metric types
├── logger.go           # Logging system
├── system.go           # Centralized monitoring
├── metrics_test.go      # Unit tests for metrics
├── logger_test.go      # Unit tests for logger
└── system_test.go      # Unit tests for system

License

This monitoring system is part of Seshat and follows the same license terms.

Contributing

For bug reports, feature requests, or contributions:

  1. Check existing issues and pull requests
  2. Follow the coding style and conventions
  3. Add tests for new features
  4. Update documentation as needed

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func InitTracer

func InitTracer(ctx context.Context, serviceName string) (shutdown func(context.Context) error, err error)

InitTracer initialises the global OTel tracer provider.

If OTEL_EXPORTER_OTLP_ENDPOINT is unset it installs a no-op provider and returns immediately — callers do not need to special-case the absence. The returned shutdown function must be called before the process exits.

By default the gRPC exporter connects without TLS (suitable for a local collector). Set OTEL_EXPORTER_OTLP_INSECURE=false to enable TLS.

func Tracer

func Tracer() trace.Tracer

Tracer returns the global named tracer for Seshat. Safe to call before InitTracer — returns a no-op tracer until the provider is initialised.

Types

type Counter

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

Counter is a metric that only increases

func NewCounter

func NewCounter(name string, labels map[string]string) *Counter

NewCounter creates a new counter metric

func (*Counter) Add

func (c *Counter) Add(delta uint64)

Add adds a value to the counter

func (*Counter) Inc

func (c *Counter) Inc()

Inc increments the counter by 1

func (*Counter) Reset

func (c *Counter) Reset()

Reset resets the counter to 0

func (*Counter) ToMetric

func (c *Counter) ToMetric() Metric

ToMetric converts the counter to a metric

func (*Counter) Value

func (c *Counter) Value() uint64

Value returns the current counter value

type Gauge

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

Gauge is a metric that can go up or down

func NewGauge

func NewGauge(name string, labels map[string]string) *Gauge

NewGauge creates a new gauge metric

func (*Gauge) Add

func (g *Gauge) Add(delta float64)

Add adds a value to the gauge

func (*Gauge) Set

func (g *Gauge) Set(value float64)

Set sets the gauge value

func (*Gauge) ToMetric

func (g *Gauge) ToMetric() Metric

ToMetric converts the gauge to a metric

func (*Gauge) Value

func (g *Gauge) Value() float64

Value returns the current gauge value

type Histogram

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

Histogram tracks the distribution of values

func NewHistogram

func NewHistogram(name string, labels map[string]string, buckets []float64) *Histogram

NewHistogram creates a new histogram metric

func (*Histogram) Average

func (h *Histogram) Average() float64

Average returns the average value

func (*Histogram) Count

func (h *Histogram) Count() uint64

Count returns the total number of observations

func (*Histogram) Observe

func (h *Histogram) Observe(value float64)

Observe records a value in the histogram

func (*Histogram) Percentile

func (h *Histogram) Percentile(percentile float64) float64

Percentile calculates the approximate percentile

func (*Histogram) Reset

func (h *Histogram) Reset()

Reset clears all observations

func (*Histogram) Sum

func (h *Histogram) Sum() float64

Sum returns the sum of all observations

func (*Histogram) ToMetric

func (h *Histogram) ToMetric() Metric

ToMetric converts the histogram to a metric

type LogLevel

type LogLevel string

LogLevel represents severity of log messages

const (
	LogLevelDebug LogLevel = "debug"
	LogLevelInfo  LogLevel = "info"
	LogLevelWarn  LogLevel = "warn"
	LogLevelError LogLevel = "error"
	LogLevelFatal LogLevel = "fatal"
)

type Logger

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

Logger represents a structured logger with context

func NewLogger

func NewLogger() *Logger

NewLogger creates a new logger with default configuration

func NewLoggerWithConfig

func NewLoggerWithConfig(config *LoggerConfig) *Logger

NewLoggerWithConfig creates a new logger with custom configuration

func (*Logger) Debug

func (l *Logger) Debug(msg string, fields map[string]interface{})

Debug logs a debug message

func (*Logger) DebugWithContext

func (l *Logger) DebugWithContext(ctx context.Context, msg string, fields map[string]interface{})

DebugWithContext logs a debug message with context

func (*Logger) Error

func (l *Logger) Error(msg string, fields map[string]interface{})

Error logs an error message

func (*Logger) ErrorWithContext

func (l *Logger) ErrorWithContext(ctx context.Context, msg string, fields map[string]interface{})

ErrorWithContext logs an error message with context

func (*Logger) ErrorWithStack

func (l *Logger) ErrorWithStack(msg string, err error, fields map[string]interface{})

ErrorWithStack logs an error message with stack trace

func (*Logger) Fatal

func (l *Logger) Fatal(msg string, fields map[string]interface{})

Fatal logs a fatal message and exits

func (*Logger) FatalWithContext

func (l *Logger) FatalWithContext(ctx context.Context, msg string, fields map[string]interface{})

FatalWithContext logs a fatal message with context and exits

func (*Logger) Info

func (l *Logger) Info(msg string, fields map[string]interface{})

Info logs an info message

func (*Logger) InfoWithContext

func (l *Logger) InfoWithContext(ctx context.Context, msg string, fields map[string]interface{})

InfoWithContext logs an info message with context

func (*Logger) LogCircuitBreakerState

func (l *Logger) LogCircuitBreakerState(ctx context.Context, from, to string, reason string)

LogCircuitBreakerState logs circuit breaker state changes

func (*Logger) LogError

func (l *Logger) LogError(ctx context.Context, err error, operation string)

LogError logs application errors with context

func (*Logger) LogRequest

func (l *Logger) LogRequest(ctx context.Context, method, url string, statusCode int, duration time.Duration)

LogRequest logs HTTP request information

func (*Logger) LogToolExecution

func (l *Logger) LogToolExecution(ctx context.Context, toolName string, duration time.Duration, success bool)

LogToolExecution logs tool execution information

func (*Logger) SetContext

func (l *Logger) SetContext(ctx context.Context) map[string]string

SetContext extracts context fields from context

func (*Logger) SetLevel

func (l *Logger) SetLevel(level LogLevel)

SetLevel updates minimum log level

func (*Logger) Warn

func (l *Logger) Warn(msg string, fields map[string]interface{})

Warn logs a warning message

func (*Logger) WarnWithContext

func (l *Logger) WarnWithContext(ctx context.Context, msg string, fields map[string]interface{})

WarnWithContext logs a warning message with context

type LoggerConfig

type LoggerConfig struct {
	// Level is minimum log level to output
	Level LogLevel `json:"level"`

	// Output is where to write logs (stdout, stderr, file)
	Output string `json:"output"`

	// FilePath is file path when Output is "file"
	FilePath string `json:"file_path"`

	// Format is log format (json, text)
	Format string `json:"format"`

	// ContextFields are additional fields to include in all log entries
	ContextFields []string `json:"context_fields"`
}

LoggerConfig represents logger configuration

func DefaultLoggerConfig

func DefaultLoggerConfig() *LoggerConfig

DefaultLoggerConfig returns default logger configuration

type Metric

type Metric struct {
	// Name is the metric name
	Name string `json:"name"`

	// Type is the metric type
	Type MetricType `json:"type"`

	// Value is the metric value
	Value float64 `json:"value"`

	// Labels are key-value pairs for categorization
	Labels map[string]string `json:"labels"`

	// Timestamp is when the metric was recorded
	Timestamp time.Time `json:"timestamp"`
}

Metric represents a single metric with labels

type MetricType

type MetricType string

MetricType represents the type of metric

const (
	MetricTypeCounter   MetricType = "counter"   // Counting events
	MetricTypeGauge     MetricType = "gauge"     // Point-in-time values
	MetricTypeHistogram MetricType = "histogram" // Distribution of values
	MetricTypeTimer     MetricType = "timer"     // Duration measurements
)

type RequestLogger

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

RequestLogger wraps HTTP client with logging

func NewRequestLogger

func NewRequestLogger(logger *Logger) *RequestLogger

NewRequestLogger creates a new request logger

func (*RequestLogger) LogRequest

func (rl *RequestLogger) LogRequest(ctx context.Context, req interface{}, resp interface{}, err error, duration time.Duration)

LogRequest logs HTTP request details

type System

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

System provides centralized monitoring for Seshat

func NewSystem

func NewSystem(logger *Logger) *System

NewSystem creates a new monitoring system

func (*System) Close

func (m *System) Close() error

Close cleans up monitoring system resources

func (*System) GetAllMetrics

func (m *System) GetAllMetrics() map[string]interface{}

GetAllMetrics returns all current metric values

func (*System) GetLogger

func (m *System) GetLogger() *Logger

GetLogger returns logger

func (*System) GetMetricsSnapshot

func (m *System) GetMetricsSnapshot(format string) (string, error)

GetMetricsSnapshot returns a snapshot of all metrics in format

func (*System) RecordAPIFailure

func (m *System) RecordAPIFailure(err error, duration time.Duration)

RecordAPIFailure records a failed API request

func (*System) RecordAPIRateLimit

func (m *System) RecordAPIRateLimit()

RecordAPIRateLimit records a rate limit hit

func (*System) RecordAPIRequest

func (m *System) RecordAPIRequest()

RecordAPIRequest records an API request

func (*System) RecordAPISuccess

func (m *System) RecordAPISuccess(duration time.Duration)

RecordAPISuccess records a successful API request

func (*System) RecordCacheStats

func (m *System) RecordCacheStats(readTokens, creationTokens int)

RecordCacheStats records Anthropic prompt cache statistics from a response. readTokens is cache_read_input_tokens, creationTokens is cache_creation_input_tokens.

func (*System) RecordCircuitBreakerStateTransition

func (m *System) RecordCircuitBreakerStateTransition(from, to string, reason string)

RecordCircuitBreakerStateTransition records a state transition

func (*System) RecordCircuitBreakerTrip

func (m *System) RecordCircuitBreakerTrip(provider string)

RecordCircuitBreakerTrip records a circuit breaker trip

func (*System) RecordError

func (m *System) RecordError(err error, context string)

RecordError records a general error

func (*System) RecordQueryFailure

func (m *System) RecordQueryFailure(err error, duration time.Duration)

RecordQueryFailure records a failed query turn

func (*System) RecordQueryIteration

func (m *System) RecordQueryIteration()

RecordQueryIteration records a query loop iteration

func (*System) RecordQuerySuccess

func (m *System) RecordQuerySuccess(duration time.Duration)

RecordQuerySuccess records a successful query turn

func (*System) RecordQueryTurn

func (m *System) RecordQueryTurn()

RecordQueryTurn records a query turn

func (*System) RecordToolCall

func (m *System) RecordToolCall(toolName string)

RecordToolCall records a tool call

func (*System) RecordToolFailure

func (m *System) RecordToolFailure(toolName string, err error, duration time.Duration)

RecordToolFailure records a failed tool call

func (*System) RecordToolPermissionDenial

func (m *System) RecordToolPermissionDenial(toolName string)

RecordToolPermissionDenial records a permission denial

func (*System) RecordToolSuccess

func (m *System) RecordToolSuccess(toolName string, duration time.Duration)

RecordToolSuccess records a successful tool call

func (*System) ResetAllMetrics

func (m *System) ResetAllMetrics()

ResetAllMetrics resets all metrics to zero

func (*System) SetCircuitBreakerState

func (m *System) SetCircuitBreakerState(state string)

SetCircuitBreakerState updates current circuit breaker state

func (*System) SetLogger

func (m *System) SetLogger(logger *Logger)

SetLogger sets logger

func (*System) UpdateActiveConnections

func (m *System) UpdateActiveConnections(count float64)

UpdateActiveConnections updates count of active connections

func (*System) UpdateActiveSessions

func (m *System) UpdateActiveSessions(count float64)

UpdateActiveSessions updates count of active sessions

func (*System) UpdateMemoryUsage

func (m *System) UpdateMemoryUsage(mb float64)

UpdateMemoryUsage updates memory usage

type Timer

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

Timer measures duration of operations

func NewTimer

func NewTimer(name string, labels map[string]string) *Timer

NewTimer creates a new timer metric

func (*Timer) Average

func (t *Timer) Average() float64

Average returns the average duration in milliseconds

func (*Timer) Count

func (t *Timer) Count() uint64

Count returns the total number of recordings

func (*Timer) Percentile

func (t *Timer) Percentile(percentile float64) time.Duration

Percentile returns the duration at the given percentile

func (*Timer) Record

func (t *Timer) Record(duration time.Duration)

Record records a duration in milliseconds

func (*Timer) Reset

func (t *Timer) Reset()

Reset clears all recordings

func (*Timer) Start

func (t *Timer) Start() func()

Start returns a function that records the elapsed time

func (*Timer) ToMetric

func (t *Timer) ToMetric() Metric

ToMetric converts the timer to a metric

Jump to

Keyboard shortcuts

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