> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fabraix.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Log Event

> Log agent events for observability and security analysis

## Overview

This endpoint receives and stores individual events from AI agents throughout their execution. Events represent distinct steps in the agent's reasoning loop (user inputs, model outputs, tool calls, etc.) and are essential for security analysis and observability.

<Info>
  Events should be logged continuously throughout the agent's lifecycle to maintain a complete audit trail.
</Info>

## Request

<ParamField body="event_type" type="enum" required>
  The category of event being logged. Must be one of:

  * `user` - Input from human users
  * `model_input` - Data sent to the LLM
  * `model_output` - Responses from the LLM
  * `tool` - Tool/function calls and results
  * `environment` - External system interactions
  * `memory` - Memory read/write operations
  * `system` - System-level events
  * `error` - Error conditions and failures
</ParamField>

<ParamField body="trace_id" type="UUID" required>
  The session identifier obtained from `/register-agent-run`. This links the event to a specific agent session.

  Example: `"f4f4f4f4-f4f4-f4f4-f4f4-f4f4f4f4f4f4"`
</ParamField>

<ParamField body="timestamp" type="float" required>
  Unix timestamp (seconds since epoch) when the event occurred.

  Example: `1678886405.123`
</ParamField>

<ParamField body="content" type="string" required>
  The event data as a stringified JSON object. Must conform to the structure defined in the `schema` field.

  Example: `"{\"location\":\"London, UK\",\"units\":\"celsius\"}"`
</ParamField>

<ParamField body="schema" type="string" required>
  A stringified JSON Schema object defining the structure of the `content` field. This enables dynamic validation and understanding of diverse event types.

  Example: `"{\"type\":\"object\",\"properties\":{\"location\":{\"type\":\"string\"},\"units\":{\"type\":\"string\"}}}"`
</ParamField>

## Response

<ResponseField name="event_id" type="UUID" required>
  Unique identifier for the logged event.

  Example: `"e1e1e1e1-e1e1-e1e1-e1e1-e1e1e1e1e1e1"`
</ResponseField>

<ResponseField name="timestamp" type="float" required>
  Server timestamp when the event was processed.

  Example: `1678886405.456`
</ResponseField>

## Event Type Examples

### User Event

Log user inputs to the agent:

<CodeGroup>
  ```python Python theme={null}
  import json
  import time

  # User message event
  user_content = {
      "message": "Can you help me book a flight to Paris?",
      "user_id": "user-123",
      "channel": "web_chat"
  }

  user_schema = {
      "type": "object",
      "properties": {
          "message": {
              "type": "string",
              "description": "User's message text"
          },
          "user_id": {
              "type": "string",
              "description": "Unique user identifier"
          },
          "channel": {
              "type": "string",
              "enum": ["web_chat", "mobile", "api"]
          }
      },
      "required": ["message", "user_id"]
  }

  response = log_event(
      event_type="user",
      trace_id=trace_id,
      timestamp=time.time(),
      content=json.dumps(user_content),
      schema=json.dumps(user_schema)
  )
  ```

  ```javascript JavaScript theme={null}
  // User message event
  const userContent = {
    message: "Can you help me book a flight to Paris?",
    user_id: "user-123",
    channel: "web_chat"
  };

  const userSchema = {
    type: "object",
    properties: {
      message: {
        type: "string",
        description: "User's message text"
      },
      user_id: {
        type: "string", 
        description: "Unique user identifier"
      },
      channel: {
        type: "string",
        enum: ["web_chat", "mobile", "api"]
      }
    },
    required: ["message", "user_id"]
  };

  const response = await logEvent({
    event_type: "user",
    trace_id: traceId,
    timestamp: Date.now() / 1000,
    content: JSON.stringify(userContent),
    schema: JSON.stringify(userSchema)
  });
  ```
</CodeGroup>

### Tool Event

Log tool/function calls:

<CodeGroup>
  ```python Python theme={null}
  # Tool call event
  tool_content = {
      "location": "Paris, France",
      "check_in": "2024-03-15",
      "check_out": "2024-03-20",
      "guests": 2
  }

  tool_schema = {
      "type": "function",
      "name": "search_hotels",
      "description": "Search for available hotels",
      "parameters": {
          "type": "object",
          "properties": {
              "location": {
                  "type": "string",
                  "description": "Destination city"
              },
              "check_in": {
                  "type": "string",
                  "format": "date"
              },
              "check_out": {
                  "type": "string",
                  "format": "date"
              },
              "guests": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 10
              }
          },
          "required": ["location", "check_in", "check_out"]
      }
  }

  response = log_event(
      event_type="tool",
      trace_id=trace_id,
      timestamp=time.time(),
      content=json.dumps(tool_content),
      schema=json.dumps(tool_schema)
  )
  ```

  ```javascript JavaScript theme={null}
  // Tool call event
  const toolContent = {
    location: "Paris, France",
    check_in: "2024-03-15",
    check_out: "2024-03-20",
    guests: 2
  };

  const toolSchema = {
    type: "function",
    name: "search_hotels",
    description: "Search for available hotels",
    parameters: {
      type: "object",
      properties: {
        location: {
          type: "string",
          description: "Destination city"
        },
        check_in: {
          type: "string",
          format: "date"
        },
        check_out: {
          type: "string",
          format: "date"
        },
        guests: {
          type: "integer",
          minimum: 1,
          maximum: 10
        }
      },
      required: ["location", "check_in", "check_out"]
    }
  };

  const response = await logEvent({
    event_type: "tool",
    trace_id: traceId,
    timestamp: Date.now() / 1000,
    content: JSON.stringify(toolContent),
    schema: JSON.stringify(toolSchema)
  });
  ```
</CodeGroup>

### Model Output Event

Log LLM responses:

```python theme={null}
# Model output event
model_content = {
    "response": "I'll help you search for hotels in Paris.",
    "tool_calls": [
        {
            "id": "call_123",
            "function": "search_hotels",
            "arguments": {
                "location": "Paris, France"
            }
        }
    ],
    "confidence": 0.95,
    "tokens_used": 45
}

model_schema = {
    "type": "object",
    "properties": {
        "response": {"type": "string"},
        "tool_calls": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "id": {"type": "string"},
                    "function": {"type": "string"},
                    "arguments": {"type": "object"}
                }
            }
        },
        "confidence": {"type": "number"},
        "tokens_used": {"type": "integer"}
    }
}
```

### Memory Event

Log memory operations:

```python theme={null}
# Memory write event
memory_content = {
    "operation": "write",
    "key": "user_preferences",
    "value": {
        "preferred_airline": "Air France",
        "seat_preference": "window",
        "meal_preference": "vegetarian"
    },
    "ttl": 86400  # 24 hours
}

memory_schema = {
    "type": "object",
    "properties": {
        "operation": {
            "type": "string",
            "enum": ["read", "write", "delete", "update"]
        },
        "key": {"type": "string"},
        "value": {"type": "object"},
        "ttl": {
            "type": "integer",
            "description": "Time to live in seconds"
        }
    },
    "required": ["operation", "key"]
}
```

## Complete Example

Here's a complete example of logging multiple events in sequence:

<CodeGroup>
  ```python Python theme={null}
  import json
  import time
  import requests

  class FabraixLogger:
      def __init__(self, api_key, trace_id):
          self.api_key = api_key
          self.trace_id = trace_id
          self.base_url = "https://api.fabraix.com/v1"
      
      def log_event(self, event_type, content, schema):
          """Log an event to Fabraix"""
          response = requests.post(
              f"{self.base_url}/event",
              headers={
                  "x-api-key": self.api_key,
                  "Content-Type": "application/json"
              },
              json={
                  "event_type": event_type,
                  "trace_id": self.trace_id,
                  "timestamp": time.time(),
                  "content": json.dumps(content),
                  "schema": json.dumps(schema)
              }
          )
          return response.json()
      
      def log_user_message(self, message, user_id):
          """Log a user message"""
          return self.log_event(
              event_type="user",
              content={
                  "message": message,
                  "user_id": user_id
              },
              schema={
                  "type": "object",
                  "properties": {
                      "message": {"type": "string"},
                      "user_id": {"type": "string"}
                  }
              }
          )
      
      def log_tool_call(self, tool_name, arguments, result=None):
          """Log a tool call"""
          content = {
              "tool": tool_name,
              "arguments": arguments
          }
          if result:
              content["result"] = result
          
          return self.log_event(
              event_type="tool",
              content=content,
              schema={
                  "type": "object",
                  "properties": {
                      "tool": {"type": "string"},
                      "arguments": {"type": "object"},
                      "result": {"type": "object"}
                  }
              }
          )

  # Usage
  logger = FabraixLogger(api_key="YOUR_KEY", trace_id="abc-123")

  # Log conversation flow
  logger.log_user_message("Book a flight to Paris", "user-456")
  logger.log_tool_call("search_flights", {"destination": "Paris"})
  logger.log_tool_call(
      "search_flights",
      {"destination": "Paris"},
      result={"flights": [{"id": "FL123", "price": 299}]}
  )
  ```

  ```javascript JavaScript theme={null}
  class FabraixLogger {
    constructor(apiKey, traceId) {
      this.apiKey = apiKey;
      this.traceId = traceId;
      this.baseUrl = 'https://api.fabraix.com/v1';
    }
    
    async logEvent(eventType, content, schema) {
      const response = await fetch(`${this.baseUrl}/event`, {
        method: 'POST',
        headers: {
          'x-api-key': this.apiKey,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          event_type: eventType,
          trace_id: this.traceId,
          timestamp: Date.now() / 1000,
          content: JSON.stringify(content),
          schema: JSON.stringify(schema)
        })
      });
      
      return response.json();
    }
    
    async logUserMessage(message, userId) {
      return this.logEvent(
        'user',
        {
          message: message,
          user_id: userId
        },
        {
          type: 'object',
          properties: {
            message: { type: 'string' },
            user_id: { type: 'string' }
          }
        }
      );
    }
    
    async logToolCall(toolName, args, result = null) {
      const content = {
        tool: toolName,
        arguments: args
      };
      
      if (result) {
        content.result = result;
      }
      
      return this.logEvent(
        'tool',
        content,
        {
          type: 'object',
          properties: {
            tool: { type: 'string' },
            arguments: { type: 'object' },
            result: { type: 'object' }
          }
        }
      );
    }
  }

  // Usage
  const logger = new FabraixLogger('YOUR_KEY', 'abc-123');

  // Log conversation flow
  await logger.logUserMessage('Book a flight to Paris', 'user-456');
  await logger.logToolCall('search_flights', { destination: 'Paris' });
  await logger.logToolCall(
    'search_flights',
    { destination: 'Paris' },
    { flights: [{ id: 'FL123', price: 299 }] }
  );
  ```
</CodeGroup>

## Response Examples

### Success Response

```json theme={null}
{
  "event_id": "e1e1e1e1-e1e1-e1e1-e1e1-e1e1e1e1e1e1",
  "timestamp": 1678886405.789
}
```

### Error Responses

<CodeGroup>
  ```json 400 Bad Request - Invalid Schema theme={null}
  {
    "error": {
      "message": "Content does not match provided schema",
      "type": "validation_error",
      "code": "SCHEMA_MISMATCH",
      "details": {
        "missing_field": "user_id",
        "path": "$.user_id"
      }
    }
  }
  ```

  ```json 404 Not Found - Invalid Trace theme={null}
  {
    "error": {
      "message": "Trace ID not found",
      "type": "not_found_error",
      "code": "TRACE_NOT_FOUND"
    }
  }
  ```

  ```json 400 Bad Request - Invalid JSON theme={null}
  {
    "error": {
      "message": "Invalid JSON in content field",
      "type": "parse_error", 
      "code": "INVALID_JSON",
      "details": {
        "position": 45,
        "line": 2
      }
    }
  }
  ```
</CodeGroup>

## Best Practices

<AccordionGroup>
  <Accordion title="Log Events Immediately">
    Log events as they occur rather than batching (unless using batch API):

    ```python theme={null}
    # Good: Immediate logging
    user_input = get_user_input()
    log_event("user", user_input)  # Log immediately

    response = process_input(user_input)
    log_event("model_output", response)  # Log immediately

    # Bad: Delayed logging
    events = []
    events.append(("user", user_input))
    # ... much later ...
    for event in events:
        log_event(*event)  # Context lost
    ```
  </Accordion>

  <Accordion title="Include Rich Context">
    Add contextual information that aids in debugging and analysis:

    ```python theme={null}
    # Good: Rich context
    content = {
        "action": "delete_file",
        "file_path": "/data/report.pdf",
        "file_size": 1024000,
        "reason": "User requested deletion",
        "user_id": "user-123",
        "ip_address": "192.168.1.1",
        "session_id": "sess-456"
    }

    # Bad: Minimal context
    content = {
        "action": "delete_file",
        "file": "report.pdf"
    }
    ```
  </Accordion>

  <Accordion title="Use Detailed Schemas">
    Provide comprehensive schemas with constraints and descriptions:

    ```python theme={null}
    # Good: Detailed schema
    schema = {
        "type": "object",
        "description": "Email sending event",
        "properties": {
            "to": {
                "type": "string",
                "format": "email",
                "description": "Recipient email"
            },
            "subject": {
                "type": "string",
                "maxLength": 200,
                "description": "Email subject line"
            },
            "priority": {
                "type": "string",
                "enum": ["low", "normal", "high"],
                "default": "normal"
            }
        },
        "required": ["to", "subject"],
        "additionalProperties": false
    }

    # Bad: Minimal schema
    schema = {"type": "object"}
    ```
  </Accordion>

  <Accordion title="Handle Errors in Events">
    Log errors as events for complete observability:

    ```python theme={null}
    try:
        result = risky_operation()
        log_event("tool", {"result": result})
    except Exception as e:
        # Log the error as an event
        log_event(
            event_type="error",
            content={
                "error": str(e),
                "error_type": e.__class__.__name__,
                "operation": "risky_operation",
                "traceback": traceback.format_exc()
            },
            schema={
                "type": "object",
                "properties": {
                    "error": {"type": "string"},
                    "error_type": {"type": "string"},
                    "operation": {"type": "string"},
                    "traceback": {"type": "string"}
                }
            }
        )
    ```
  </Accordion>

  <Accordion title="Asynchronous Logging">
    Use async logging to minimize latency:

    ```python theme={null}
    import asyncio
    from concurrent.futures import ThreadPoolExecutor

    class AsyncLogger:
        def __init__(self, api_key, trace_id):
            self.api_key = api_key
            self.trace_id = trace_id
            self.executor = ThreadPoolExecutor(max_workers=5)
        
        async def log_event_async(self, event_type, content, schema):
            loop = asyncio.get_event_loop()
            return await loop.run_in_executor(
                self.executor,
                self._log_event_sync,
                event_type,
                content,
                schema
            )
        
        def _log_event_sync(self, event_type, content, schema):
            # Synchronous API call
            return log_event(
                self.trace_id,
                event_type,
                content,
                schema
            )
    ```
  </Accordion>
</AccordionGroup>

## Performance Considerations

### Batch Logging

For high-volume applications, consider batching events:

```python theme={null}
class EventBatcher:
    def __init__(self, api_key, trace_id, batch_size=50):
        self.api_key = api_key
        self.trace_id = trace_id
        self.batch = []
        self.batch_size = batch_size
    
    def add_event(self, event_type, content, schema):
        self.batch.append({
            "event_type": event_type,
            "trace_id": self.trace_id,
            "timestamp": time.time(),
            "content": json.dumps(content),
            "schema": json.dumps(schema)
        })
        
        if len(self.batch) >= self.batch_size:
            self.flush()
    
    def flush(self):
        if self.batch:
            # Send batch to API (future feature)
            send_batch(self.batch)
            self.batch = []
```

### Content Size Limits

Be mindful of content size:

* Maximum content size: 1MB
* Maximum schema size: 64KB
* For large data, consider storing externally and logging references

```python theme={null}
# For large content, store externally
if len(content_str) > 900000:  # Near 1MB limit
    # Store in S3/database
    reference_id = store_external(content_str)
    
    # Log reference instead
    log_event(
        event_type="environment",
        content={
            "type": "external_reference",
            "reference_id": reference_id,
            "size_bytes": len(content_str)
        },
        schema=reference_schema
    )
```

## Related Endpoints

* [POST /register-agent-run](/api-reference/arx/endpoint/register-agent-run) - Register a session before logging events
* [POST /check](/api-reference/arx/endpoint/check) - Validate actions based on logged events

## FAQ

<AccordionGroup>
  <Accordion title="Can I log events out of order?">
    Yes, events can arrive out of order. The timestamp field is used to establish the correct sequence. However, logging events as they occur is recommended for real-time analysis.
  </Accordion>

  <Accordion title="What happens if schema validation fails?">
    The event will be rejected with a 400 error detailing the validation failure. Fix the content to match the schema or update the schema to match the content.
  </Accordion>

  <Accordion title="How detailed should schemas be?">
    Schemas should be as detailed as possible. Include types, constraints, enums, and descriptions. This helps Fabraix better understand your agent's behavior.
  </Accordion>

  <Accordion title="Is there a limit on events per session?">
    There's no hard limit on events per session, but extremely long sessions (>10,000 events) may experience degraded performance. Consider creating new sessions for long-running agents periodically.
  </Accordion>
</AccordionGroup>
