Go agent for capturing exceptions and panics with full context and local variables.
- Go 1.21 or higher
go get github.com/aivory/aivory-monitor-goCurrently available as:
go get github.com/ilscipio/aivory-monitor/agent-gopackage main
import (
"github.com/ilscipio/aivory-monitor/agent-go/pkg/agent"
)
func main() {
// Initialize agent with API key
agent.Init(
agent.WithAPIKey("your-api-key"),
agent.WithEnvironment("production"),
)
defer agent.Shutdown()
// Your application code
}The agent captures panics using Go's defer and recover mechanism. IMPORTANT: agent.CapturePanic() must be deferred to work correctly.
func handleRequest() {
defer agent.CapturePanic()
// Your code that might panic
processData()
}For nested recovery (capture and continue):
func handleRequest() {
defer func() {
if r := recover(); r != nil {
// Handle recovery (log, cleanup, etc.)
fmt.Printf("Recovered: %v\n", r)
}
}()
defer agent.CapturePanic() // Captures then re-panics
// Your code
}func processOrder(orderID string) error {
order, err := fetchOrder(orderID)
if err != nil {
// Capture error with context
agent.CaptureError(err, map[string]interface{}{
"order_id": orderID,
"operation": "fetch_order",
})
return err
}
return nil
}package main
import (
"fmt"
"net/http"
"github.com/ilscipio/aivory-monitor/agent-go/pkg/agent"
)
func aivoryMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer agent.CapturePanic()
// Set request context
agent.SetContext(map[string]interface{}{
"path": r.URL.Path,
"method": r.Method,
"ip": r.RemoteAddr,
})
next.ServeHTTP(w, r)
})
}
func main() {
agent.Init(agent.WithAPIKey("your-api-key"))
defer agent.Shutdown()
mux := http.NewServeMux()
mux.HandleFunc("/", handleHome)
http.ListenAndServe(":8080", aivoryMiddleware(mux))
}
func handleHome(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}// Set user information for all subsequent captures
agent.SetUser(
"user-123", // User ID
"[email protected]", // Email
"john_doe", // Username
)
// Set custom context
agent.SetContext(map[string]interface{}{
"tenant_id": "org-456",
"feature_flags": []string{"new-ui", "beta-api"},
})| Variable | Description | Default |
|---|---|---|
AIVORY_API_KEY |
Agent authentication key | Required |
AIVORY_BACKEND_URL |
Backend WebSocket URL | wss://api.aivory.net/monitor/agent |
AIVORY_ENVIRONMENT |
Environment name | production |
AIVORY_SAMPLING_RATE |
Exception sampling (0-1) | 1.0 |
AIVORY_MAX_DEPTH |
Variable capture depth | 10 |
AIVORY_MAX_STRING_LENGTH |
Max string length in captures | 1000 |
AIVORY_MAX_COLLECTION_SIZE |
Max array/map size in captures | 100 |
AIVORY_DEBUG |
Enable debug logging | false |
agent.Init(
// Required
agent.WithAPIKey("your-api-key"),
// Optional
agent.WithBackendURL("wss://api.aivory.net/monitor/agent"),
agent.WithEnvironment("staging"),
agent.WithSamplingRate(0.5), // Sample 50% of errors
agent.WithDebug(true), // Enable debug logs
)WithAPIKey(key string)- Set API keyWithBackendURL(url string)- Set backend WebSocket URLWithEnvironment(env string)- Set environment nameWithSamplingRate(rate float64)- Set sampling rate (0.0-1.0)WithDebug(debug bool)- Enable/disable debug logging
cd monitor-agents/agent-go
go mod tidy
go build ./pkg/agentThe agent uses Go's built-in defer and recover mechanism to capture panics. When agent.CapturePanic() is deferred, it:
- Calls
recover()to capture the panic value - Extracts stack trace and local variables
- Sends exception data to the backend via WebSocket
- Re-panics to maintain normal panic behavior
The agent is goroutine-safe and uses sync.RWMutex to protect shared state. You can safely call agent methods from multiple goroutines.
The agent maintains a persistent WebSocket connection to the backend:
- Automatic reconnection on disconnect
- Heartbeat for connection monitoring
- Buffered message queue during connection loss
The agent automatically handles SIGINT and SIGTERM signals for graceful shutdown:
agent.Init(agent.WithAPIKey("..."))
// Agent will automatically shutdown on SIGINT/SIGTERM
// Or manual shutdown
defer agent.Shutdown()cd monitor-agents/agent-go
# Set environment variables
export AIVORY_API_KEY=ilscipio-dev-2024
export AIVORY_BACKEND_URL=ws://localhost:19999/ws/monitor/agent
export AIVORY_DEBUG=true
# Run test application
go run ./cmd/testapp/The test app triggers various panic types:
- Nil pointer dereference (index out of range)
- Explicit panic with string message
- Nil map assignment
- Backend running on
localhost:19999 - Dev token bypass enabled (uses
ilscipio-dev-2024) - Org schema
org_test_20exists in database
Agent not connecting:
- Check backend is running:
curl http://localhost:19999/health - Verify WebSocket endpoint:
ws://localhost:19999/ws/monitor/agent - Check API key is set correctly
- Enable debug mode with
agent.WithDebug(true)
Panics not being captured:
- Ensure
defer agent.CapturePanic()is called before the panic - Remember that
recover()only works in deferred functions - Check that the agent is initialized before panic occurs
High memory usage:
- Reduce
AIVORY_MAX_DEPTHto capture fewer nested variables - Reduce
AIVORY_MAX_COLLECTION_SIZEfor large arrays/maps - Lower
AIVORY_SAMPLING_RATEto capture fewer exceptions
WebSocket connection issues:
- Check firewall rules for WebSocket connections
- Verify backend URL includes protocol (
ws://orwss://) - Check backend logs for connection errors
- Enable debug logging to see connection attempts