CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-eliot-tree

Render Eliot logs as an ASCII tree

Pending
Overview
Eval results
Files

filtering.mddocs/

Filtering

Advanced filtering capabilities for selective processing of Eliot tasks based on various criteria. Filters work on the original Eliot message dictionaries before task parsing, enabling efficient selection using JMESPath queries, UUID matching, timestamp ranges, and logical combinations.

Imports

from datetime import datetime
from iso8601 import parse_date

Capabilities

JMESPath Query Filtering

Create filter functions using JMESPath query expressions to select tasks based on any field or condition in the original Eliot message structure.

def filter_by_jmespath(query):
    """
    Produce a function for filtering a task by a JMESPath query expression.

    Parameters:
    - query: str - JMESPath query string used as a predicate

    Returns:
    Callable[[dict], bool] - Filter function that returns True if task matches query
    """

Usage Examples:

from eliottree import filter_by_jmespath

# Filter tasks containing a 'uri' field
uri_filter = filter_by_jmespath('uri')

# Filter by specific action type
http_filter = filter_by_jmespath('action_type == `"http_client:request"`')

# Filter by HTTP status codes
error_filter = filter_by_jmespath('contains(`[401, 500]`, status)')

# Complex filtering with multiple conditions
critical_filter = filter_by_jmespath(
    'http_status == `401` && uri && contains(uri, `"/criticalEndpoint"`)'
)

# Apply filter to messages
filtered_tasks = [task for task in tasks if uri_filter(task)]

UUID-Based Filtering

Filter entire task trees by their unique identifier, useful for isolating specific request flows or debugging particular operations.

def filter_by_uuid(task_uuid):
    """
    Produce a function for filtering tasks by their UUID.
    
    Implementation note: This is implemented as a JMESPath wrapper that creates
    a query equivalent to: task_uuid == `<uuid_value>`

    Parameters:
    - task_uuid: str - UUID string to match against task_uuid field

    Returns:
    Callable[[dict], bool] - Filter function for UUID matching
    """

Usage Example:

from eliottree import filter_by_uuid

# Filter by specific task UUID
uuid_filter = filter_by_uuid("f3a32bb3-ea6b-457c-aa99-08a3d0491ab4")

# Apply filter
specific_tasks = [task for task in tasks if uuid_filter(task)]

Timestamp-Based Filtering

Filter tasks based on their occurrence time using start and end date boundaries, enabling time-range analysis of log data.

def filter_by_start_date(start_date):
    """
    Produce a function for filtering by task timestamps after (or on) a certain date and time.

    Parameters:
    - start_date: datetime - Tasks must occur at or after this datetime

    Returns:
    Callable[[dict], bool] - Filter function for start date filtering
    """

def filter_by_end_date(end_date):
    """
    Produce a function for filtering by task timestamps before a certain date and time.

    Parameters:
    - end_date: datetime - Tasks must occur before this datetime

    Returns:
    Callable[[dict], bool] - Filter function for end date filtering
    """

Usage Examples:

from datetime import datetime
from iso8601 import parse_date
from eliottree import filter_by_start_date, filter_by_end_date

# Filter tasks after a specific time
start_time = parse_date("2015-03-03T04:28:00Z")
after_filter = filter_by_start_date(start_time)

# Filter tasks before a specific time
end_time = parse_date("2015-03-03T04:30:00Z")
before_filter = filter_by_end_date(end_time)

# Apply filters
recent_tasks = [task for task in tasks if after_filter(task)]
time_range_tasks = [task for task in tasks 
                   if after_filter(task) and before_filter(task)]

Logical Filter Combination

Combine multiple filter functions using logical AND operations to create sophisticated filtering criteria.

def combine_filters_and(*filters):
    """
    Combine several filters together in a logical-AND fashion.

    Parameters:
    - *filters: Variable number of filter functions

    Returns:
    Callable[[Any], bool] - Combined filter function that returns True only 
                           if all input filters return True
    """

Usage Examples:

from eliottree import (
    filter_by_jmespath, filter_by_start_date, filter_by_end_date,
    combine_filters_and
)

# Combine multiple filters
error_filter = filter_by_jmespath('http_status == `401`')
uri_filter = filter_by_jmespath('uri && contains(uri, `"/api"`)')
time_filter = filter_by_start_date(parse_date("2015-03-03T04:00:00Z"))

# Create combined filter
combined_filter = combine_filters_and(error_filter, uri_filter, time_filter)

# Apply combined filter
filtered_tasks = [task for task in tasks if combined_filter(task)]

Complete Filtering Pipeline

import json
from datetime import datetime
from iso8601 import parse_date
from eliottree import (
    tasks_from_iterable, render_tasks, get_theme,
    filter_by_jmespath, filter_by_start_date, combine_filters_and
)

def process_filtered_logs(log_file, start_time_str, action_type):
    """Process logs with multiple filtering criteria."""
    
    # Load messages
    with open(log_file, 'r') as f:
        messages = [json.loads(line) for line in f]
    
    # Create filters
    time_filter = filter_by_start_date(parse_date(start_time_str))
    action_filter = filter_by_jmespath(f'action_type == `"{action_type}"`')
    
    # Combine filters
    combined_filter = combine_filters_and(time_filter, action_filter)
    
    # Apply filtering
    filtered_messages = [msg for msg in messages if combined_filter(msg)]
    
    # Process and render
    tasks = tasks_from_iterable(filtered_messages)
    theme = get_theme(dark_background=True)
    render_tasks(sys.stdout.write, tasks, theme=theme)

# Usage
process_filtered_logs(
    'eliot.log', 
    '2015-03-03T04:28:00Z', 
    'http_client:request'
)

Filter Function Composition

Filters can be composed and reused for different analysis scenarios:

# Define reusable filters
def create_error_filters():
    return {
        'http_errors': filter_by_jmespath('status >= `400`'),
        'timeout_errors': filter_by_jmespath('contains(error_type || `""`, `"timeout"`)'),
        'auth_errors': filter_by_jmespath('status == `401` || status == `403`'),
    }

def create_time_range_filter(start_str, end_str):
    start_filter = filter_by_start_date(parse_date(start_str))
    end_filter = filter_by_end_date(parse_date(end_str))
    return combine_filters_and(start_filter, end_filter)

# Usage
error_filters = create_error_filters()
time_range = create_time_range_filter('2015-03-03T04:00:00Z', '2015-03-03T05:00:00Z')

# Combine for specific analysis
auth_errors_in_range = combine_filters_and(
    error_filters['auth_errors'], 
    time_range
)

JMESPath Query Patterns

Common query patterns for Eliot log analysis:

# Existence checks
filter_by_jmespath('uri')                    # Has URI field
filter_by_jmespath('error_message')          # Has error message

# Exact matches
filter_by_jmespath('action_type == `"http_request"`')
filter_by_jmespath('status == `200`')

# Numeric comparisons
filter_by_jmespath('status >= `400`')        # HTTP errors
filter_by_jmespath('duration > `5.0`')      # Slow operations

# String operations
filter_by_jmespath('contains(uri, `"/api/"`)')
filter_by_jmespath('starts_with(action_type, `"db:"`)')

# Array operations
filter_by_jmespath('contains(`[401, 403, 500]`, status)')
filter_by_jmespath('length(task_level) > `2`')

# Complex conditions
filter_by_jmespath('status >= `400` && contains(uri, `"/critical"`)')

Install with Tessl CLI

npx tessl i tessl/pypi-eliot-tree

docs

core-processing.md

errors.md

filtering.md

index.md

theming.md

tile.json