Documentation
¶
Overview ¶
Package productgraph provides a client for sending events to ProductGraph and middleware for frontend-backend correlation.
Package productgraph provides a client for sending telemetry events to ProductGraph and middleware for frontend-backend correlation.
Overview ¶
ProductGraph is a product analytics platform that collects and analyzes user behavior events from both frontend and backend systems. This package enables Go services to:
- Send events to ProductGraph with batching and async dispatch
- Correlate backend requests with frontend sessions
- Track API calls, errors, and journey steps
Quick Start ¶
// Create client
client, err := productgraph.New(productgraph.Config{
ProjectID: "my-project",
Endpoint: "https://api.productgraph.io/v1/events",
APIKey: os.Getenv("PRODUCTGRAPH_API_KEY"),
})
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Use middleware for automatic tracking
r := chi.NewRouter()
r.Use(productgraph.ChainMiddleware(client))
// Or track events manually
client.TrackAPICall(ctx, "POST", "/checkout", 200, 150*time.Millisecond)
client.TrackJourneyStep(ctx, "checkout_flow", "payment", "Enter Payment")
client.TrackError(ctx, "ValidationError", "invalid card number")
Correlation ¶
The CorrelationMiddleware extracts frontend correlation headers and injects them into the request context:
- X-Session-ID: Frontend session identifier
- X-Request-ID: Per-request identifier (generated if not provided)
- X-User-ID: Authenticated user identifier
Use SessionIDFromContext, RequestIDFromContext, and UserIDFromContext to retrieve these values in your handlers.
Event Types ¶
ProductGraph supports various event types following OTel semantic conventions:
- page.view, page.leave: Page navigation
- ui.click, ui.input, ui.scroll, ui.submit: User interactions
- state.change: Application state changes
- api.request, api.response: API calls
- journey.step: User journey progression
- error: Application errors
- performance: Performance metrics
Configuration ¶
Use ConfigFromEnv to load configuration from environment variables:
- PRODUCTGRAPH_PROJECT_ID: Project identifier
- PRODUCTGRAPH_ENDPOINT: API endpoint
- PRODUCTGRAPH_API_KEY: Authentication key
- PRODUCTGRAPH_BATCH_SIZE: Events per batch (default: 50)
- PRODUCTGRAPH_BATCH_INTERVAL: Flush interval in seconds (default: 5)
- PRODUCTGRAPH_DEBUG: Enable debug logging
Index ¶
- Constants
- Variables
- func ChainMiddleware(client *Client) func(http.Handler) http.Handler
- func CorrelationMiddleware(next http.Handler) http.Handler
- func RequestIDFromContext(ctx context.Context) string
- func RequestTrackerMiddleware(client *Client) func(http.Handler) http.Handler
- func SessionIDFromContext(ctx context.Context) string
- func UserIDFromContext(ctx context.Context) string
- func WithRequestID(ctx context.Context, requestID string) context.Context
- func WithSessionID(ctx context.Context, sessionID string) context.Context
- func WithUserID(ctx context.Context, userID string) context.Context
- type Client
- func (c *Client) Close() error
- func (c *Client) Config() Config
- func (c *Client) Flush(ctx context.Context) error
- func (c *Client) IsEnabled() bool
- func (c *Client) SetLogger(logger *slog.Logger)
- func (c *Client) Track(ctx context.Context, event Event) error
- func (c *Client) TrackAPICall(ctx context.Context, method, path string, statusCode int, ...) error
- func (c *Client) TrackError(ctx context.Context, errType, message string) error
- func (c *Client) TrackJourneyStep(ctx context.Context, journeyID, stepID, stepName string) error
- type Config
- type ContextKey
- type Event
- type EventType
- type Payload
- type PayloadError
- type Response
Constants ¶
const ( // HeaderSessionID is the HTTP header for session ID from frontend. HeaderSessionID = "X-Session-ID" // HeaderRequestID is the HTTP header for request ID. HeaderRequestID = "X-Request-ID" // HeaderUserID is the HTTP header for user ID. HeaderUserID = "X-User-ID" )
Variables ¶
var ( ErrMissingProjectID = errors.New("productgraph: missing project_id") ErrMissingEndpoint = errors.New("productgraph: missing endpoint") ErrClientClosed = errors.New("productgraph: client is closed") )
Common errors.
Functions ¶
func ChainMiddleware ¶
ChainMiddleware chains correlation and request tracking middleware. This is a convenience function that applies both middlewares in the correct order: 1. CorrelationMiddleware - extracts session/request IDs 2. RequestTrackerMiddleware - tracks API calls with correlation
func CorrelationMiddleware ¶
CorrelationMiddleware extracts correlation headers from incoming requests and injects them into the request context. It also generates a request ID if not provided and echoes it back in the response.
func RequestIDFromContext ¶
RequestIDFromContext extracts the request ID from context. Returns empty string if not present.
func RequestTrackerMiddleware ¶
RequestTrackerMiddleware creates middleware that tracks HTTP requests to ProductGraph. It records api.response events with method, path, status code, and duration.
func SessionIDFromContext ¶
SessionIDFromContext extracts the session ID from context. Returns empty string if not present.
func UserIDFromContext ¶
UserIDFromContext extracts the user ID from context. Returns empty string if not present.
func WithRequestID ¶
WithRequestID returns a new context with the request ID set.
func WithSessionID ¶
WithSessionID returns a new context with the session ID set.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client sends events to ProductGraph with batching and async dispatch.
func (*Client) Track ¶
Track queues an event for dispatch to ProductGraph. The event is buffered and sent asynchronously in batches.
func (*Client) TrackAPICall ¶
func (c *Client) TrackAPICall(ctx context.Context, method, path string, statusCode int, duration time.Duration) error
TrackAPICall is a convenience method for tracking API calls.
func (*Client) TrackError ¶
TrackError is a convenience method for tracking errors.
type Config ¶
type Config struct {
// ProjectID is the ProductGraph project identifier (required).
ProjectID string
// Endpoint is the ProductGraph API endpoint (required).
// Example: "https://api.productgraph.io/v1/events"
Endpoint string
// APIKey is the API key for authentication (optional).
// Sent as X-PG-API-Key header.
APIKey string
// BatchSize is the number of events to buffer before flushing.
// Default: 50
BatchSize int
// BatchInterval is the maximum time to wait before flushing buffered events.
// Default: 5 seconds
BatchInterval time.Duration
// HTTPClient is the HTTP client to use for requests.
// Default: http.DefaultClient with 10s timeout
HTTPClient *http.Client
// Debug enables debug logging.
Debug bool
}
Config holds ProductGraph client configuration.
func ConfigFromEnv ¶
func ConfigFromEnv() Config
ConfigFromEnv creates a Config from environment variables.
Environment variables:
- PRODUCTGRAPH_PROJECT_ID: Project identifier (required)
- PRODUCTGRAPH_ENDPOINT: API endpoint (required)
- PRODUCTGRAPH_API_KEY: API key for authentication
- PRODUCTGRAPH_BATCH_SIZE: Events per batch (default: 50)
- PRODUCTGRAPH_BATCH_INTERVAL: Flush interval in seconds (default: 5)
- PRODUCTGRAPH_DEBUG: Enable debug logging (true/false)
func (Config) WithDefaults ¶
WithDefaults returns a copy of the config with default values applied.
type ContextKey ¶
type ContextKey string
ContextKey is used for storing correlation values in context.
const ( // SessionIDKey is the context key for session ID. SessionIDKey ContextKey = "productgraph.session_id" // RequestIDKey is the context key for request ID. RequestIDKey ContextKey = "productgraph.request_id" // UserIDKey is the context key for user ID. UserIDKey ContextKey = "productgraph.user_id" )
type Event ¶
type Event struct {
// Identity
EventID string `json:"event_id"`
ProjectID string `json:"project_id"`
SessionID string `json:"session.id"`
UserID string `json:"user.id,omitempty"`
// Event classification
EventType EventType `json:"event.type"`
EventName string `json:"event.name,omitempty"`
Timestamp string `json:"event.timestamp"`
Sequence int `json:"event.sequence,omitempty"`
// Page context
PagePath string `json:"page.path,omitempty"`
PageTitle string `json:"page.title,omitempty"`
PageURL string `json:"page.url,omitempty"`
PageReferrer string `json:"page.referrer,omitempty"`
// UI context
UIComponentName string `json:"ui.component.name,omitempty"`
UIComponentPath string `json:"ui.component.path,omitempty"`
UIComponentType string `json:"ui.component.type,omitempty"`
UIAction string `json:"ui.action,omitempty"`
UIElement string `json:"ui.element,omitempty"`
UIElementText string `json:"ui.element.text,omitempty"`
// State changes
UIStateKey string `json:"ui.state.key,omitempty"`
UIStateBefore string `json:"ui.state.before,omitempty"`
UIStateAfter string `json:"ui.state.after,omitempty"`
// Journey tracking
JourneyID string `json:"gen_ai.journey.id,omitempty"`
JourneyStep string `json:"gen_ai.journey.step.id,omitempty"`
JourneyName string `json:"gen_ai.journey.step.name,omitempty"`
// API tracking
APIMethod string `json:"api.method,omitempty"`
APIPath string `json:"api.path,omitempty"`
APIStatusCode int `json:"api.status_code,omitempty"`
APIDurationMs int `json:"api.duration_ms,omitempty"`
// Error tracking
ErrorType string `json:"error.type,omitempty"`
ErrorMessage string `json:"error.message,omitempty"`
ErrorStack string `json:"error.stack,omitempty"`
// Performance
DurationMs int `json:"duration_ms,omitempty"`
// Organization
OrgID string `json:"org.id,omitempty"`
OrgName string `json:"org.name,omitempty"`
// Custom metadata
Metadata map[string]any `json:"metadata,omitempty"`
}
Event represents a ProductGraph event following OTel semantic conventions.
func APIResponseEvent ¶
APIResponseEvent creates an event for tracking an API response.
func ErrorEvent ¶
ErrorEvent creates an event for tracking an error.
func JourneyStepEvent ¶
JourneyStepEvent creates an event for tracking a journey step.
type EventType ¶
type EventType string
EventType represents the type of ProductGraph event.
const ( // Page events EventTypePageView EventType = "page.view" EventTypePageLeave EventType = "page.leave" // UI events EventTypeUIClick EventType = "ui.click" EventTypeUIInput EventType = "ui.input" EventTypeUIScroll EventType = "ui.scroll" EventTypeUIFocus EventType = "ui.focus" EventTypeUIBlur EventType = "ui.blur" EventTypeUISubmit EventType = "ui.submit" // State events EventTypeStateChange EventType = "state.change" // API events EventTypeAPIRequest EventType = "api.request" EventTypeAPIResponse EventType = "api.response" // Journey events EventTypeJourneyStep EventType = "journey.step" // Error events EventTypeError EventType = "error" // Performance events EventTypePerformance EventType = "performance" // Custom events EventTypeCustom EventType = "custom" )
type Payload ¶
type Payload struct {
Events []Event `json:"events"`
}
Payload represents the request body for POST /v1/events.
type PayloadError ¶
PayloadError represents an error for a specific event in a batch.
type Response ¶
type Response struct {
Accepted int `json:"accepted"`
Rejected int `json:"rejected"`
Errors []PayloadError `json:"errors,omitempty"`
}
Response represents the response from POST /v1/events.