Custom Views

Custom Views

Custom Views allow you to create virtual tables that extract specific fields from your log data using JSON path expressions. This feature enables you to organize and analyze your log data with custom columns tailored to your specific use cases, without modifying the underlying data structure.

⚠️

Feature Flag Required: Custom Views is currently gated behind a feature flag. Please reach out to RunReveal support to request access to this feature.

Getting Started: Navigate to Settings → Custom Views to create your first custom view, or use the CLI and API for programmatic access.

Key Features

  • Virtual Tables: Create queryable views without data transformation
  • JSON Path Extraction: Extract nested fields from your raw logs
  • Source Filtering: Views automatically filter to specific sources
  • Real-time Analysis: Query-time extraction for immediate insights
  • Flexible Schema: Add custom columns for any JSON field in your logs

When to Use Custom Views

✅ Perfect For:

  • Field Extraction: Pull specific fields from complex JSON logs
  • Analysis Enhancement: Add columns for security analysis, compliance, or investigation
  • Source-Specific Views: Create specialized views for different log sources
  • Query Optimization: Pre-define commonly used field extractions

❌ Not Ideal For:

  • Data Normalization: Use transforms to map fields to standard RunReveal schema
  • Complex Logic: Limited to simple JSON path expressions (no SQL functions)
  • Data Transformation: Views are read-only, no data modification

Architecture

Raw Log → Transform (Optional) → runreveal.logs → Custom View → Analysis
    ↓           ↓                    ↓              ↓           ↓
  Your       Field Mapping      Standardized    Virtual     Queries
  JSON       to Standard        Data            Table       & Alerts

Creating Custom Views

Via Web UI

1) Navigate to Custom Views

Go to Settings → Custom Views and click “Create Custom View”.

2) Configure Basic Information

Fill in the basic information:

  • Name: Descriptive name for your view
  • Description: Optional description of the view’s purpose
  • Source: Select the source to filter logs from

3) Add Custom Columns

Add custom columns with:

  • Column Name: Name for the extracted field
  • Type: ClickHouse data type (String, Int64, Bool, etc.)
  • SQL Expression: JSON path to extract the field
  • Description: Optional description of the column

4) Test and Save

Test your view with sample data, then save your configuration.

Via CLI

# List existing custom views
./runreveal custom-views list
 
# Create a new custom view
./runreveal custom-views create \
  --name "my_custom_view" \
  --description "Description of the view" \
  --source-id "your_source_id" \
  --columns '[{"name": "field_name", "type": "String", "sql": "json.path", "description": "Field description"}]'
 
# Get a specific view
./runreveal custom-views get --id "view_id"
 
# Update a view
./runreveal custom-views update --id "view_id" [flags]
 
# Delete a view
./runreveal custom-views delete --id "view_id"

Via API

# Create custom view
curl -X POST "https://api.runreveal.com/custom-views/create" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my_custom_view",
    "description": "Description of the view",
    "sourceId": "your_source_id",
    "columns": [
      {
        "name": "field_name",
        "description": "Field description",
        "type": "String",
        "sql": "json.path"
      }
    ]
  }'

Column Configuration

Supported Data Types

TypeDescriptionExample
StringText data"[email protected]"
Int6464-bit integer12345
UInt64Unsigned 64-bit integer4294967295
Float6464-bit floating point3.14159
BoolBoolean valuetrue
DateTimeDate and time2025-01-15 10:30:00
Array(String)Array of strings["tag1", "tag2"]
Nullable(String)Nullable stringnull or "value"

JSON Path Expressions

Custom views support simple JSON path expressions to extract nested fields:

Basic Syntax

field.subfield.array[0].nested_field

Examples

{
  "user": {
    "profile": {
      "email": "[email protected]"
    }
  },
  "tags": ["security", "alert"],
  "metadata": {
    "source_ip": "192.168.1.100"
  }
}

Valid JSON Paths:

  • user.profile.email"[email protected]"
  • tags[0]"security"
  • metadata.source_ip"192.168.1.100"

Limitations

  • No SQL Functions: Cannot use CASE, COALESCE, IF, etc.
  • No Conditional Logic: Cannot use OR, AND statements
  • Simple Paths Only: Only direct field access and array indexing

Example: Jamf Protect Custom View

Use Case

Extract important security fields from Jamf Protect Device Telemetry Stream logs for analysis.

Configuration

Basic Information:

  • Name: jamf_protect_telemetry
  • Description: Jamf Protect Device Telemetry Stream analysis
  • Source: Your Jamf Protect source

Custom Columns:

[
  {
    "name": "jamf_event_type",
    "description": "Jamf event type classification",
    "type": "String",
    "sql": "event_type"
  },
  {
    "name": "jamf_hostname",
    "description": "Device hostname",
    "type": "String",
    "sql": "host.hostname"
  },
  {
    "name": "jamf_device_serial",
    "description": "Device serial number",
    "type": "String",
    "sql": "host.serial"
  },
  {
    "name": "jamf_os_version",
    "description": "OS version",
    "type": "String",
    "sql": "host.os"
  },
  {
    "name": "jamf_protect_version",
    "description": "Jamf Protect agent version",
    "type": "String",
    "sql": "host.protectVersion"
  },
  {
    "name": "jamf_client_id",
    "description": "Jamf client ID",
    "type": "String",
    "sql": "context.identity.claims.clientid"
  },
  {
    "name": "jamf_organization",
    "description": "Organization context",
    "type": "String",
    "sql": "context.identity.claims.hd"
  },
  {
    "name": "jamf_actor_username",
    "description": "User who performed the action",
    "type": "String",
    "sql": "event.exec.target.audit_token.e_username"
  },
  {
    "name": "jamf_process_path",
    "description": "Executable path",
    "type": "String",
    "sql": "event.exec.target.executable.path"
  },
  {
    "name": "jamf_signing_id",
    "description": "Code signing identity",
    "type": "String",
    "sql": "event.exec.target.signing_id"
  },
  {
    "name": "jamf_is_platform_binary",
    "description": "Is Apple-signed binary",
    "type": "Bool",
    "sql": "event.exec.target.is_platform_binary"
  },
  {
    "name": "jamf_executable_sha256",
    "description": "File integrity hash",
    "type": "String",
    "sql": "event.exec.target.executable.sha256"
  }
]

Querying Custom Views

View Naming Convention

Custom views are named using the pattern: {workspace_name}_{view_name}

Example: runreveal_inc_jamf_protect_telemetry

Basic Queries

-- Get all records from the custom view
SELECT * FROM your_workspace_jamf_protect_telemetry LIMIT 10;
 
-- Get specific columns
SELECT 
  eventTime,
  jamf_event_type,
  jamf_hostname,
  jamf_actor_username
FROM your_workspace_jamf_protect_telemetry
ORDER BY eventTime DESC;

Security Analysis Queries

-- Find non-platform binary executions
SELECT 
  eventTime,
  jamf_hostname,
  jamf_actor_username,
  jamf_process_path,
  jamf_signing_id,
  jamf_is_platform_binary
FROM your_workspace_jamf_protect_telemetry
WHERE jamf_is_platform_binary = false
ORDER BY eventTime DESC
LIMIT 100;
 
-- Find process executions by specific user
SELECT 
  eventTime,
  jamf_process_path,
  jamf_executable_sha256,
  jamf_signing_id
FROM your_workspace_jamf_protect_telemetry
WHERE jamf_actor_username = 'suspicious_user'
ORDER BY eventTime DESC;
 
-- Find unsigned or suspiciously signed binaries
SELECT 
  eventTime,
  jamf_hostname,
  jamf_process_path,
  jamf_signing_id
FROM your_workspace_jamf_protect_telemetry
WHERE jamf_signing_id NOT LIKE 'com.apple.%'
  AND jamf_signing_id != ''
ORDER BY eventTime DESC;

Combining with Transforms

Best Practice: Hybrid Approach

Use transforms for standard field mapping and custom views for source-specific analysis:

Transform (Data Normalization)

{
  "processors": [
    {
      "type": "field_mapper",
      "config": {
        "mappings": [
          {
            "source": "event_type",
            "target": "eventName"
          },
          {
            "source": "host.hostname",
            "target": "serviceName"
          },
          {
            "source": "host.ips[0]",
            "target": "srcIP"
          },
          {
            "source": "event.exec.target.audit_token.e_username",
            "target": "actor.username"
          }
        ]
      }
    }
  ]
}

Custom View (Analysis Enhancement)

[
  {
    "name": "jamf_signing_id",
    "type": "String",
    "sql": "event.exec.target.signing_id"
  },
  {
    "name": "jamf_is_platform_binary",
    "type": "Bool", 
    "sql": "event.exec.target.is_platform_binary"
  }
]

Benefits

  • Standard Fields: Work with existing RunReveal detections
  • Custom Fields: Enable advanced source-specific analysis
  • Flexibility: Query either standard table or custom view as needed

Using Custom Views in Detections

Custom views can be targeted in detection rules:

title: Suspicious Process Execution
detection:
  selection:
    jamf_is_platform_binary: false
    jamf_signing_id:
      - "com.suspicious.app"
      - ""
  condition: selection
sourcenames:
  - your_jamf_source

Limitations and Considerations

Current Limitations

  • No SQL Functions: Cannot use CASE, COALESCE, IF, etc.
  • No Conditional Logic: Cannot use OR, AND statements
  • Simple JSON Paths Only: Limited to direct field access
  • Read-Only: Views cannot modify data

Workarounds

  • Multiple Columns: Create separate columns for different field paths
  • Query-Time Logic: Use COALESCE in your queries to combine fields
  • Transforms: Use transforms for complex field mapping

Performance Considerations

  • Query-Time Extraction: Fields are extracted during query execution
  • Indexing: Custom view columns are not indexed separately
  • Large Datasets: Consider query performance with large log volumes

Troubleshooting

Common Issues

”Invalid JSON path” Error

  • Cause: JSON path syntax is incorrect
  • Solution: Use simple dot notation: field.subfield.array[0]

”No rows in result set”

  • Cause: No logs match the source filter or time range
  • Solution: Check source is active and has recent logs

”Column not found” Error

  • Cause: Column name doesn’t exist in the view
  • Solution: Verify column names match the custom view definition

Debugging Steps

  1. Check Source: Verify the source is active and receiving logs
  2. Verify JSON Path: Test the JSON path against sample log data
  3. Check Data Types: Ensure column types match the extracted data
  4. Review Logs: Check for any error messages in the RunReveal logs

Best Practices

Design Guidelines

  • Descriptive Names: Use clear, descriptive column names
  • Consistent Types: Use appropriate data types for extracted fields
  • Documentation: Add descriptions to explain column purposes
  • Source-Specific: Create views tailored to specific log sources

Performance Tips

  • Limit Columns: Only extract fields you actually need
  • Appropriate Types: Use the most specific data type possible
  • Query Optimization: Use WHERE clauses to limit result sets
  • Time Ranges: Always include time-based filters in queries

Security Considerations

  • Sensitive Data: Be careful not to expose sensitive information in custom columns
  • Access Control: Custom views inherit workspace permissions
  • Audit Trail: Monitor who creates and modifies custom views

Helpful Resources

Getting Help

  • Documentation: This guide and inline help in the UI
  • Support: Contact RunReveal support for technical issues
  • Community: Join the RunReveal community for best practices
  • Transforms: For data normalization and field mapping
  • Detections: For alerting on custom view data
  • Pipelines: For complex data processing workflows
  • Query Builder: For interactive query construction