Noveum.ai
Noveum docs

Events - Point-in-Time Occurrences

Understanding events and how they track point-in-time occurrences during trace execution

Events are point-in-time occurrences that happen during the execution of a trace or span. They provide a timeline of what happened, when it happened, and what the context was at that moment.

🎯 What are Events?

Events represent:

  • State changes during operation execution
  • Important milestones in your application flow
  • Error conditions and recovery actions
  • User interactions and system responses
  • Business logic decisions and outcomes

🏗️ Event Structure

Every event has:

  • Name: Descriptive name of what happened
  • Timestamp: When the event occurred
  • Attributes: Key-value metadata about the event
  • Span Context: Which span the event belongs to

📊 Event Categories

Operation Events

# Start and completion events
span.add_event("operation.started", {
    "timestamp": time.time(),
    "input.size": len(input_data),
    "input.type": "json"
})

span.add_event("operation.completed", {
    "timestamp": time.time(),
    "output.size": len(output_data),
    "success": True,
    "duration_ms": 1800
})

AI Events

# Model selection and response events
span.add_event("ai.model.selected", {
    "timestamp": time.time(),
    "model": "gpt-4",
    "reason": "complex_query",
    "fallback_used": False
})

span.add_event("ai.response.generated", {
    "timestamp": time.time(),
    "tokens_used": 200,
    "finish_reason": "stop",
    "response_time_ms": 1800
})

Business Events

# Customer interaction events
span.add_event("customer.query.received", {
    "timestamp": time.time(),
    "query.length": 45,
    "query.sentiment": "neutral",
    "customer.tier": "premium"
})

span.add_event("customer.query.processed", {
    "timestamp": time.time(),
    "processing_time_ms": 2000,
    "confidence_score": 0.85,
    "response.quality": "high"
})

Error Events

# Error tracking events
span.add_event("error.occurred", {
    "timestamp": time.time(),
    "error.type": "APIError",
    "error.message": "Rate limit exceeded",
    "error.retry_count": 3,
    "error.retry_after": 60
})

span.add_event("error.recovered", {
    "timestamp": time.time(),
    "recovery.action": "retry_with_backoff",
    "recovery.success": True,
    "total_retry_time_ms": 5000
})

🔄 Adding Events

Basic Event

span.add_event("user.login.attempted", {
    "timestamp": time.time(),
    "user.id": "user_123",
    "login.method": "email"
})

Event with Rich Context

span.add_event("ai.model.switched", {
    "timestamp": time.time(),
    "from.model": "gpt-3.5-turbo",
    "to.model": "gpt-4",
    "reason": "complex_query_detected",
    "query.complexity_score": 0.85,
    "fallback.triggered": True
})

Conditional Events

# Add events based on conditions
if response.confidence < 0.7:
    span.add_event("low.confidence.detected", {
        "timestamp": time.time(),
        "confidence.score": response.confidence,
        "threshold": 0.7,
        "action.taken": "escalate_to_human"
    })

🎯 Event Naming Conventions

Hierarchical Naming

Use dot notation to create logical hierarchies:

# Customer events
"customer.query.received"
"customer.query.processed"
"customer.query.completed"

# AI events
"ai.model.selected"
"ai.response.generated"
"ai.error.occurred"

# System events
"system.cache.hit"
"system.cache.miss"
"system.retry.attempted"

Action-Based Naming

Use action verbs to describe what happened:

# Good: Action-based naming
"user.login.attempted"
"user.login.succeeded"
"user.login.failed"
"ai.model.switched"
"ai.response.generated"

# Bad: State-based naming
"user.logged_in"
"ai.model_is_gpt4"
"ai.response_ready"

📈 Event Attributes

Timestamp Attributes

span.add_event("operation.started", {
    "timestamp": time.time(),
    "timestamp.iso": "2024-01-15T10:30:00Z",
    "timestamp.unix": 1705312200
})

Context Attributes

span.add_event("ai.model.selected", {
    "timestamp": time.time(),
    "context.query_type": "technical_support",
    "context.customer_tier": "premium",
    "context.complexity_score": 0.85
})

Result Attributes

span.add_event("ai.response.generated", {
    "timestamp": time.time(),
    "result.tokens_used": 200,
    "result.finish_reason": "stop",
    "result.quality_score": 0.92
})

Error Attributes

span.add_event("error.occurred", {
    "timestamp": time.time(),
    "error.type": "APIError",
    "error.code": 429,
    "error.message": "Rate limit exceeded",
    "error.retry_count": 3,
    "error.retry_after": 60
})

🎪 Event Patterns

Start/Complete Pattern

with trace_operation("process-query") as span:
    # Start event
    span.add_event("operation.started", {
        "timestamp": time.time(),
        "input.size": len(query),
        "input.type": "text"
    })
    
    try:
        # Process the query
        result = process_query(query)
        
        # Complete event
        span.add_event("operation.completed", {
            "timestamp": time.time(),
            "output.size": len(result),
            "success": True,
            "duration_ms": time.time() - start_time
        })
        
    except Exception as e:
        # Error event
        span.add_event("operation.failed", {
            "timestamp": time.time(),
            "error.type": type(e).__name__,
            "error.message": str(e),
            "duration_ms": time.time() - start_time
        })
        raise

State Change Pattern

with trace_operation("ai-completion") as span:
    # Initial state
    span.add_event("ai.initialization", {
        "timestamp": time.time(),
        "model": "gpt-3.5-turbo",
        "temperature": 0.7
    })
    
    # State change
    if query_complexity > 0.8:
        span.add_event("ai.model.upgraded", {
            "timestamp": time.time(),
            "from.model": "gpt-3.5-turbo",
            "to.model": "gpt-4",
            "reason": "high_complexity"
        })
    
    # Final state
    span.add_event("ai.completion.ready", {
        "timestamp": time.time(),
        "final.model": "gpt-4",
        "tokens.estimated": 200
    })

Retry Pattern

with trace_operation("api-call") as span:
    retry_count = 0
    max_retries = 3
    
    while retry_count <= max_retries:
        try:
            span.add_event("api.call.attempted", {
                "timestamp": time.time(),
                "attempt": retry_count + 1,
                "max_retries": max_retries
            })
            
            result = make_api_call()
            
            span.add_event("api.call.succeeded", {
                "timestamp": time.time(),
                "attempt": retry_count + 1,
                "duration_ms": time.time() - start_time
            })
            
            break
            
        except Exception as e:
            retry_count += 1
            
            span.add_event("api.call.failed", {
                "timestamp": time.time(),
                "attempt": retry_count,
                "error.type": type(e).__name__,
                "error.message": str(e),
                "will_retry": retry_count <= max_retries
            })
            
            if retry_count > max_retries:
                raise

🔍 Event Analysis

Timeline Analysis

Events provide a timeline of what happened:

# Find all events for a specific trace
events = get_trace_events(trace_id)

# Sort by timestamp
events.sort(key=lambda e: e.timestamp)

# Analyze the timeline
for event in events:
    print(f"{event.timestamp}: {event.name} - {event.attributes}")

Event Frequency

# Count events by type
event_counts = count_events_by_type(trace_id)

# Find common event patterns
common_events = find_common_event_patterns(traces)

Error Analysis

# Find all error events
error_events = find_events(trace_id, event_name="error.occurred")

# Analyze error patterns
error_patterns = analyze_error_patterns(error_events)

🚀 Next Steps

Now that you understand events, explore these related concepts:

Best Practices


Events provide the timeline and context that make your traces meaningful. They enable detailed analysis, debugging, and optimization of your AI applications.