Module: Tasker::Concerns::StructuredLogging

Overview

StructuredLogging provides correlation ID tracking and consistent JSON formatting

This concern builds on Tasker’s existing event system to add production-grade structured logging with correlation IDs for distributed tracing across workflows.

Key Features:

  • Automatic correlation ID generation and propagation

  • JSON structured logging with consistent format

  • Integration with existing telemetry configuration

  • Parameter filtering for sensitive data

  • Performance-optimized with minimal overhead

Usage:

include Tasker::Concerns::StructuredLogging

# Basic structured logging
log_structured(:info, "Task started", task_id: task.task_id)

# Domain-specific helpers
log_task_event(task, :started, execution_mode: 'async')
log_step_event(step, :completed, duration: 1.5)

# Correlation ID propagation
with_correlation_id(request_id) do
  # All logging within this block includes the correlation ID
  log_structured(:info, "Processing workflow")
end

Constant Summary collapse

CORRELATION_ID_KEY =

Thread-local storage for correlation ID to ensure thread safety

:tasker_correlation_id

Instance Method Summary collapse

Instance Method Details

#correlation_idString

Get the current correlation ID, generating one if needed

Returns:

  • (String)

    The correlation ID for the current execution context



83
84
85
# File 'lib/tasker/concerns/structured_logging.rb', line 83

def correlation_id
  Thread.current[CORRELATION_ID_KEY] ||= generate_correlation_id
end

#correlation_id=(id) ⇒ String

Set a specific correlation ID for the current execution context

Parameters:

  • id (String)

    The correlation ID to use

Returns:

  • (String)

    The correlation ID that was set



91
92
93
# File 'lib/tasker/concerns/structured_logging.rb', line 91

def correlation_id=(id)
  Thread.current[CORRELATION_ID_KEY] = id
end

#log_exception(exception, context: {}, level: :error) ⇒ void

This method returns an undefined value.

Log exceptions with full context and structured format

Examples:

log_exception(e, operation: "step_execution", step_id: "step_123")
log_exception(e, operation: "task_finalization", task_id: "task_456", level: :fatal)

Parameters:

  • exception (Exception)

    The exception to log

  • context (Hash) (defaults to: {})

    Additional context about when/where the exception occurred

  • level (Symbol) (defaults to: :error)

    Log level (defaults to :error)



229
230
231
232
233
234
235
236
237
238
239
# File 'lib/tasker/concerns/structured_logging.rb', line 229

def log_exception(exception, context: {}, level: :error)
  exception_context = {
    entity_type: 'exception',
    exception_class: exception.class.name,
    exception_message: exception.message,
    backtrace: extract_relevant_backtrace(exception),
    **context
  }

  log_structured(level, "Exception occurred: #{exception.class.name}", **exception_context)
end

#log_orchestration_event(operation, event_type, **context) ⇒ void

This method returns an undefined value.

Log orchestration events (workflow coordination, reenqueuing, etc.)

Examples:

log_orchestration_event("workflow_coordination", :started, task_id: "task_123")
log_orchestration_event("step_execution_batch", :completed,
  step_count: 3, total_duration: 5.2)

Parameters:

  • operation (String)

    The orchestration operation name

  • event_type (Symbol)

    The type of event (:started, :completed, :failed, etc.)

  • context (Hash)

    Additional context to include in the log



182
183
184
185
186
187
188
# File 'lib/tasker/concerns/structured_logging.rb', line 182

def log_orchestration_event(operation, event_type, **context)
  log_structured(:debug, "Orchestration #{event_type}",
                 entity_type: 'orchestration',
                 operation: operation,
                 event_type: event_type,
                 **context)
end

#log_performance_event(operation, duration, **context) ⇒ void

This method returns an undefined value.

Log performance-related events with timing and resource usage

Examples:

log_performance_event("dependency_graph_analysis", 0.85,
  node_count: 25, complexity: "medium")
log_performance_event("sql_query", 2.1,
  query_type: "select", table: "workflow_steps")

Parameters:

  • operation (String)

    The operation being measured

  • duration (Float)

    Duration in seconds

  • context (Hash)

    Additional performance context



202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/tasker/concerns/structured_logging.rb', line 202

def log_performance_event(operation, duration, **context)
  performance_context = {
    entity_type: 'performance',
    operation: operation,
    duration_ms: (duration * 1000).round(2),
    performance_category: categorize_duration(duration),
    is_slow: duration > telemetry_config.slow_query_threshold_seconds
  }

  level = performance_context[:is_slow] ? :warn : :debug
  log_structured(level, 'Performance measurement', **performance_context, **context)
end

#log_step_event(step, event_type, duration: nil, **context) ⇒ void

This method returns an undefined value.

Log step-related events with standardized format

Examples:

log_step_event(step, :started)
log_step_event(step, :completed, duration: 2.5, records_processed: 150)
log_step_event(step, :failed, duration: 1.2, error: "Connection timeout")

Parameters:

  • step (Tasker::WorkflowStep)

    The step object

  • event_type (Symbol)

    The type of event (:started, :completed, :failed, etc.)

  • duration (Float, nil) (defaults to: nil)

    Execution duration in seconds

  • context (Hash)

    Additional context to include in the log



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/tasker/concerns/structured_logging.rb', line 151

def log_step_event(step, event_type, duration: nil, **context)
  step_context = {
    entity_type: 'step',
    entity_id: step.workflow_step_id,
    entity_name: step.name,
    event_type: event_type,
    step_status: step.status,
    task_id: step.task.task_id,
    task_name: step.task.name
  }

  # Add performance data if provided
  if duration
    step_context[:duration_ms] = (duration * 1000).round(2)
    step_context[:performance_category] = categorize_duration(duration)
  end

  log_structured(:info, "Step #{event_type}", **step_context, **context)
end

#log_structured(level, message, **context) ⇒ void

This method returns an undefined value.

Log with structured JSON format including correlation ID and context

Examples:

Basic usage

log_structured(:info, "Task execution started",
  task_id: "task_123",
  task_name: "order_processing"
)

With performance data

log_structured(:debug, "Step completed successfully",
  step_id: "step_456",
  duration_ms: 250.5,
  memory_delta_mb: 12.3
)

Parameters:

  • level (Symbol)

    Log level (:debug, :info, :warn, :error, :fatal)

  • message (String)

    Human-readable log message

  • context (Hash)

    Additional structured context data



63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/tasker/concerns/structured_logging.rb', line 63

def log_structured(level, message, **context)
  return unless should_log?(level)

  structured_data = build_structured_log_entry(message, context)
  filtered_data = apply_parameter_filtering(structured_data)

  Rails.logger.public_send(level, format_log_output(filtered_data))
rescue StandardError => e
  # Failsafe logging - never let logging errors break application flow
  Rails.logger.error("Structured logging failed: #{e.message}")
  Rails.logger.public_send(level, message) # Fallback to simple logging
end

#log_task_event(task, event_type, **context) ⇒ void

This method returns an undefined value.

Log task-related events with standardized format

Examples:

log_task_event(task, :started, execution_mode: 'async', priority: 'high')
log_task_event(task, :completed, duration: 120.5, step_count: 5)
log_task_event(task, :failed, error: exception.message)

Parameters:

  • task (Tasker::Task)

    The task object

  • event_type (Symbol)

    The type of event (:started, :completed, :failed, etc.)

  • context (Hash)

    Additional context to include in the log



129
130
131
132
133
134
135
136
137
# File 'lib/tasker/concerns/structured_logging.rb', line 129

def log_task_event(task, event_type, **context)
  log_structured(:info, "Task #{event_type}",
                 entity_type: 'task',
                 entity_id: task.task_id,
                 entity_name: task.name,
                 event_type: event_type,
                 task_status: task.status,
                 **context)
end

#with_correlation_id(id) { ... } ⇒ Object

Execute a block with a specific correlation ID

Examples:

with_correlation_id("req_abc123") do
  process_workflow
  # All logging within this block will include req_abc123
end

Parameters:

  • id (String)

    The correlation ID to use during block execution

Yields:

  • Block to execute with the correlation ID

Returns:

  • (Object)

    The result of the yielded block



106
107
108
109
110
111
112
# File 'lib/tasker/concerns/structured_logging.rb', line 106

def with_correlation_id(id)
  previous_id = Thread.current[CORRELATION_ID_KEY]
  Thread.current[CORRELATION_ID_KEY] = id
  yield
ensure
  Thread.current[CORRELATION_ID_KEY] = previous_id
end