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

# Axiom Logging & Analytics

> Guide to Axiom logging integration, MCP server setup, and report generation in CONA

# Axiom Logging & Analytics

CONA uses [Axiom](https://axiom.co/) for centralized logging, observability, and analytics. This guide explains how our Axiom integration works, how to set up the MCP server for Cursor, and how to generate reports from Axiom data.

## Overview

Axiom provides centralized log aggregation and analysis for the CONA application. It collects logs from:

* **Webapp** (`cona_webapp` dataset): Next.js application logs, server actions, API routes, and web vitals
* **Temporal Workers** (`cona_temporal-workers` dataset): Temporal workflow and activity logs

All logs are automatically enriched with metadata including organization IDs, user IDs, request paths, and error stack traces.

## Integration Architecture

### Server-Side Logging (Next.js)

Server-side logging uses the Axiom JavaScript SDK with Next.js formatters:

```typescript theme={null}
// apps/webapp/lib/axiom/server.ts
import { Logger, AxiomJSTransport } from "@axiomhq/logging";
import axiomClient from "@/lib/axiom/axiom";

export const logger = new Logger({
  transports: [
    new AxiomJSTransport({
      axiom: axiomClient,
      dataset: process.env.NEXT_PUBLIC_AXIOM_DATASET,
    }),
  ],
  formatters: axiomNextJs?.nextJsFormatters,
});
```

### Application Logger

The application uses a centralized logger function that automatically sends logs to Axiom:

```typescript theme={null}
// apps/webapp/app/lib/logger.ts
import { log } from "@/app/lib/logger";

// Basic usage
await log({
  message: "Operation completed successfully",
  level: "info",
  metadata: {
    organizationId: "org_123",
    userId: "user_456",
    action: "document_created",
  },
});

// Error logging
await log({
  message: "Failed to process document",
  level: "error",
  error: error instanceof Error ? error : new Error("Unknown error"),
  metadata: {
    documentId: "doc_789",
    organizationId: "org_123",
  },
});
```

**Log Levels:**

* `info`: General informational messages
* `warning`: Warning messages for expected issues
* `error`: Error messages for failures and exceptions

### Client-Side Logging

Client-side logs are sent through a proxy API route to keep tokens server-side:

```typescript theme={null}
// apps/webapp/lib/axiom/client.ts
import { Logger, ProxyTransport } from "@axiomhq/logging";

export const logger = new Logger({
  transports: [
    new ProxyTransport({
      url: "/api/axiom/ingest",
    }),
  ],
  formatters: nextJsFormatters,
});
```

### Temporal Workers Logging

Temporal workers use Pino with Axiom transport:

```typescript theme={null}
// apps/temporal-workers/src/logger.ts
import pino from "pino";

export function createLogger(name?: string) {
  const logger = pino(
    { level: logLevel, name },
    pino.transport({
      target: "@axiomhq/pino",
      options: {
        dataset: "cona_temporal-workers",
        token: process.env.NEXT_PUBLIC_AXIOM_TOKEN,
      },
    })
  );
  return logger;
}
```

## Axiom MCP Server Setup

The Axiom MCP (Model Context Protocol) server allows you to query Axiom datasets directly from Cursor using natural language queries.

### Prerequisites

1. **Cursor with Agent Mode**: Ensure you're using Cursor with Agent mode enabled
2. **Axiom API Token**: You'll need the Cursor Query API Key from Axiom (contact Egor for access)

### Configuration

Add the Axiom MCP server to your Cursor configuration. The MCP server configuration should be added to your Cursor settings:

```json theme={null}
{
  "mcpServers": {
    "axiom": {
      "url": "https://mcp.axiom.co/mcp",
      "headers": {}
    }
  }
}
```

**Note**: The API token is handled automatically by the MCP server - you don't need to include it in the configuration.

### Getting the API Token

To get the Cursor Query API Key:

1. Navigate to [Axiom API Tokens](https://app.axiom.co/cona-sty0/settings/api-tokens/9bc152c1e112dcfbefe9f6cdac678bc236b9a43f45908f6a24d180c159ed66be)
2. Or contact **Egor** for access to the token

### Setup Guide

For detailed setup instructions, see the [Axiom MCP Server documentation](https://axiom.co/docs/console/intelligence/mcp-server#cursor).

## Using Axiom MCP in Cursor

Once configured, you can query Axiom datasets directly from Cursor using natural language.

### Example Queries

* **"Give me the list of Axiom datasets"**
* **"Generate me a report for all warnings from cona\_webapp dataset for the last 3 days"**
* **"Show me all errors from cona\_webapp in production for the last 7 days"**
* **"What are the most common error messages in cona\_temporal-workers?"**

### Query Capabilities

The MCP server supports:

* **Dataset Listing**: List all available datasets
* **Field Discovery**: Get schema information for datasets
* **Query Execution**: Run APL (Axiom Processing Language) queries
* **Report Generation**: Generate formatted reports from query results
* **Dashboard Access**: View and retrieve dashboard information
* **Monitor Status**: Check monitor statuses and history

### Query Language (APL)

Axiom uses APL (Axiom Processing Language) for queries. Most queries start with the dataset name in square brackets:

```apl theme={null}
['cona_webapp'] | where ['level'] == "error" | summarize count() by ['message']
```

## Report Generation

Axiom reports are automatically generated in a standardized format when requested through Cursor.

### Report Location

Reports are stored in: `.reports/axiom/`

If the directory doesn't exist, Cursor will create it automatically. If creation fails, you can create it manually:

```bash theme={null}
mkdir -p .reports/axiom
```

### Report Format

Each report follows a standardized structure:

1. **YAML Frontmatter**: Contains metadata about the report
2. **Summary**: High-level overview of findings
3. **Context**: Background and assumptions
4. **Findings**: Key observations and data points
5. **Analysis**: Detailed interpretation
6. **Conclusions**: Derived conclusions
7. **Next Actions**: Recommended follow-up steps

### Report Naming

Reports are named using the format: `DD-MM-YYYY-hh:mm:ss.md`

Example: `22-01-2026-21:46:37.md`

### Report Index

All reports are automatically indexed in: `.reports/axiom/index.md`

The index lists all reports in reverse chronological order (newest first).

### Example Report Request

```
"Generate me a report of traces from cona_webapp dataset.
Use level == 'error' or level == 'ERROR'.
Use vercel.environment == 'production'.
I want a report for the last 7 days."
```

This will:

1. Query the `cona_webapp` dataset
2. Filter for errors in production
3. Analyze the last 7 days of data
4. Generate a comprehensive report with findings and recommendations

## Available Datasets

### cona\_webapp

**Type**: Next.js application logs

**Description**: Contains logs from the Next.js web application, including:

* Server actions
* API routes
* Request/response logs
* Web vitals
* Error traces
* Authentication events

**Key Fields**:

* `level`: Log level (info, warning, error)
* `message`: Log message
* `org_id`: Organization ID
* `user_id`: User ID
* `path`: Request path
* `vercel.environment`: Deployment environment (production, preview, development)
* `request.*`: Request metadata (method, path, headers, etc.)
* `fields.*`: Custom metadata fields

### cona\_temporal-workers

**Type**: Events

**Description**: Contains logs from Temporal workers, including:

* Workflow execution logs
* Activity logs
* Error traces
* Performance metrics

**Key Fields**:

* Log level and message
* Workflow/activity identifiers
* Execution metadata
* Error information

## Configuration

### Environment Variables

Required environment variables for Axiom integration:

```bash theme={null}
# Axiom API token (for ingestion and queries)
NEXT_PUBLIC_AXIOM_TOKEN=your_token_here

# Dataset name for webapp logs
NEXT_PUBLIC_AXIOM_DATASET=cona_webapp

# Dataset name for Temporal workers (in temporal-workers app)
NEXT_PUBLIC_AXIOM_DATASET=cona_temporal-workers
```

### Git Configuration

The reports directory is excluded from version control:

```gitignore theme={null}
# .gitignore
.reports/
```

This ensures generated reports don't clutter the repository while keeping them available locally.

## Best Practices

### 1. Use the Centralized Logger

Always use the centralized logger function instead of direct Axiom calls:

```typescript theme={null}
// ✅ Correct
import { log } from "@/app/lib/logger";

await log({
  message: "Operation completed",
  level: "info",
  metadata: { organizationId, userId },
});

// ❌ Incorrect - direct Axiom calls
import { logger } from "@/lib/axiom/server";
logger.info("Operation completed");
```

### 2. Include Context in Metadata

Always include relevant context in log metadata:

```typescript theme={null}
await log({
  message: "Document created",
  level: "info",
  metadata: {
    organizationId, // Always include org context
    userId, // Include user context when available
    documentId, // Include relevant entity IDs
    documentType, // Include relevant entity types
    action: "createDocument", // Include action name
  },
});
```

### 3. Error Logging

Always log errors with full context:

```typescript theme={null}
try {
  // Your code
} catch (error) {
  await log({
    message: "Failed to process document",
    level: "error",
    error: error instanceof Error ? error : new Error("Unknown error"),
    metadata: {
      documentId,
      organizationId,
      action: "processDocument",
    },
  });

  // Handle error...
}
```

### 4. Log Levels

Use appropriate log levels:

* **`info`**: Normal operations, successful actions, important events
* **`warning`**: Expected issues (validation failures, auth failures, etc.)
* **`error`**: Unexpected failures, exceptions, bugs

### 5. Query Best Practices

When querying Axiom datasets:

* **Always restrict time ranges**: Use `where ['_time'] > ago(7d)` to limit data scanned
* **Use aggregations**: Prefer `summarize` over raw data when possible
* **Project specific fields**: Only select fields you need
* **Start with dataset name**: Most queries should start with `['dataset-name']`

## Security Monitoring

Axiom serves as CONA's centralized security monitoring and intrusion detection system. All security events are automatically logged and monitored in real-time.

### Key Security Detection Rules

1. **Brute Force Detection** - Failed login attempts (>5 in 1 minute)
2. **Unauthorized Access** - 401/403 errors on protected routes
3. **API Rate Limiting** - Excessive API requests (>100/min)
4. **Admin Access Monitoring** - All `/admin` route access logged
5. **Session Hijacking** - Same session from multiple IPs
6. **Suspicious Data Access** - Unusual database query patterns
7. **Geographic Anomalies** - Logins from multiple countries in 24h
8. **Error Patterns** - Security-related errors (SQL injection, XSS attempts)
9. **Data Exfiltration** - Excessive downloads (>100MB in 30min)
10. **Database Failures** - Connection failures indicating DDoS

### Security Queries

**Detect brute force attempts:**

```apl theme={null}
['cona_webapp']
| where ['_time'] >= ago(5m)
| where ['action'] == "auth_required" and ['blocked'] == true
| summarize failures = count() by ['ip'], bin(['_time'], 1m)
| where failures > 5
```

**Monitor admin access:**

```apl theme={null}
['cona_webapp']
| where ['_time'] >= ago(1h)
| where ['request.path'] contains "/admin"
| project ['_time'], ['ip'], ['user_id'], ['request.path'], ['status']
| sort by ['_time'] desc
```

**Detect API abuse:**

```apl theme={null}
['cona_webapp']
| where ['_time'] >= ago(1m)
| where ['request.path'] startswith "/api/"
| summarize requests = count() by ['ip'], ['user_id']
| where requests > 100
```

### Alert Configuration

**Critical Alerts** (Immediate response):

* Brute force attacks (>10 failed logins/min)
* Session hijacking (session from multiple IPs)
* Database connection failures (>5 failures/min)

**High Alerts** (Response within 1 hour):

* Unauthorized access attempts (>10 in 15min)
* Suspicious error patterns (>3 security errors/10min)
* Unusual download activity (>100MB/30min)

**Medium Alerts** (Response within 24 hours):

* API rate limit violations (>100 requests/min)
* Suspicious data access patterns
* Anomalous geographic access (>2 countries/24h)

### Compliance

✅ **Centralized Logging** - All security events logged\
✅ **Intrusion Detection** - 10 detection rules covering OWASP Top 10\
✅ **Access Monitoring** - All admin/privileged access logged\
✅ **Real-time Alerts** - Critical alerts within 1 minute\
✅ **Retention** - 12-month log retention for security events

### Log Retention Policy

* **Security Events:** 12 months (audit compliance)
* **Access Logs:** 12 months (German accounting compliance)
* **Error Logs:** 6 months
* **Info Logs:** 3 months

***

## Troubleshooting

### Reports Not Generating

If report generation fails:

1. **Check directory exists**: Ensure `.reports/axiom/` directory exists
2. **Check MCP connection**: Verify Axiom MCP server is configured correctly
3. **Check API token**: Ensure you have access to the Cursor Query API Key
4. **Check query syntax**: Verify your query uses valid APL syntax

### Logs Not Appearing in Axiom

If logs aren't appearing in Axiom:

1. **Check environment variables**: Verify `NEXT_PUBLIC_AXIOM_TOKEN` and `NEXT_PUBLIC_AXIOM_DATASET` are set
2. **Check dataset name**: Ensure the dataset exists in Axiom
3. **Check network**: Verify the application can reach Axiom's API
4. **Check logger flush**: Ensure `logger.flush()` is called (handled automatically in the centralized logger)

### MCP Server Connection Issues

If the MCP server isn't working:

1. **Verify configuration**: Check that the MCP server is properly configured in Cursor
2. **Check API token**: Contact Egor to verify API token access
3. **Restart Cursor**: Sometimes a restart is needed after configuration changes
4. **Check Axiom status**: Verify Axiom service is operational

## Contact

For questions or issues related to Axiom:

* **API Token Access**: Contact **Egor**
* **Configuration Issues**: Check the [Axiom MCP documentation](https://axiom.co/docs/console/intelligence/mcp-server#cursor)
* **Dataset Access**: Verify you have access to the CONA organization in Axiom

## Additional Resources

* [Axiom Documentation](https://axiom.co/docs)
* [Axiom MCP Server Guide](https://axiom.co/docs/console/intelligence/mcp-server#cursor)
* [APL Query Language Reference](https://axiom.co/docs/apl/introduction)
