• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nshkrdotcom / ElixirScope / 54864980f2b3e3397dcc4e1db9ff6129f085bbe2

28 May 2025 03:25PM UTC coverage: 60.023% (+0.01%) from 60.013%
54864980f2b3e3397dcc4e1db9ff6129f085bbe2

push

github

NSHkr
create updated docs

5680 of 9463 relevant lines covered (60.02%)

3630.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

22.97
/lib/elixir_scope/core/event_manager.ex
1
defmodule ElixirScope.Core.EventManager do
2
  @moduledoc """
3
  Manages runtime event querying and filtering.
4
  
5
  Bridges RuntimeCorrelator with main API to provide user-facing event querying
6
  capabilities. This module translates high-level query requests into specific
7
  RuntimeCorrelator operations.
8
  """
9
  
10
  alias ElixirScope.ASTRepository.RuntimeCorrelator
11
  alias ElixirScope.Storage.EventStore
12
  alias ElixirScope.Query.Engine
13
  alias ElixirScope.Utils
14
  
15
  @type event_query :: [
16
    pid: pid() | :all,
17
    event_type: atom() | :all,
18
    since: integer() | DateTime.t(),
19
    until: integer() | DateTime.t(),
20
    limit: pos_integer()
21
  ]
22
  
23
  @doc """
24
  Gets events based on query criteria.
25
  
26
  Delegates to RuntimeCorrelator for actual event retrieval and applies
27
  filtering based on the query parameters.
28
  """
29
  @spec get_events(event_query()) :: {:ok, [map()]} | {:error, term()}
30
  def get_events(opts \\ []) do
31
    # Try to use the new EventStore first
32
    case get_default_event_store() do
19✔
33
      {:ok, store} ->
34
        # Use the new Query Engine and EventStore
35
        case Engine.execute_query(store, opts) do
14✔
36
          {:ok, events} -> {:ok, events}
14✔
37
          {:error, reason} -> {:error, reason}
×
38
        end
39
      
40
      {:error, :no_store} ->
41
        # Fall back to RuntimeCorrelator if EventStore is not available
42
        fallback_to_runtime_correlator(opts)
5✔
43
    end
44
  end
45
  
46
  @doc """
47
  Gets events with a specific query filter.
48
  
49
  Provides more advanced querying capabilities with custom filter functions.
50
  """
51
  @spec get_events_with_query(map() | function()) :: {:ok, [map()]} | {:error, term()}
52
  def get_events_with_query(query) when is_map(query) do
53
    # Convert map query to keyword list
54
    opts = Map.to_list(query)
×
55
    get_events(opts)
×
56
  end
57
  
58
  def get_events_with_query(query_fn) when is_function(query_fn, 1) do
59
    # Get all events and apply custom filter function
60
    case get_events([]) do
×
61
      {:ok, events} ->
62
        filtered_events = Enum.filter(events, query_fn)
×
63
        {:ok, filtered_events}
64
      
65
      {:error, reason} ->
×
66
        {:error, reason}
67
    end
68
  end
69
  
70
  def get_events_with_query(_query) do
×
71
    {:error, :invalid_query_format}
72
  end
73
  
74
  @doc """
75
  Gets events for a specific AST node.
76
  
77
  Provides direct access to AST-correlated events through RuntimeCorrelator.
78
  """
79
  @spec get_events_for_ast_node(binary()) :: {:ok, [map()]} | {:error, term()}
80
  def get_events_for_ast_node(ast_node_id) when is_binary(ast_node_id) do
81
    case RuntimeCorrelator.get_events_for_ast_node(ast_node_id) do
×
82
      {:ok, events} -> {:ok, events}
×
83
      {:error, reason} -> {:error, {:ast_query_failed, reason}}
×
84
    end
85
  end
86
  
87
  @doc """
88
  Gets correlation statistics from RuntimeCorrelator.
89
  """
90
  @spec get_correlation_statistics() :: {:ok, map()} | {:error, term()}
91
  def get_correlation_statistics do
92
    case RuntimeCorrelator.get_statistics() do
×
93
      {:ok, stats} -> {:ok, stats}
×
94
      {:error, reason} -> {:error, {:stats_unavailable, reason}}
×
95
    end
96
  end
97
  
98
  #############################################################################
99
  # Private Helper Functions
100
  #############################################################################
101
  
102
  defp extract_time_range(opts) do
103
    current_time = Utils.monotonic_timestamp()
×
104
    
105
    # Default to last hour if no time range specified
106
    default_start = current_time - (60 * 60 * 1000)  # 1 hour ago
×
107
    default_end = current_time
×
108
    
109
    start_time = case Keyword.get(opts, :since) do
×
110
      nil -> default_start
×
111
      %DateTime{} = dt -> DateTime.to_unix(dt, :millisecond)
×
112
      timestamp when is_integer(timestamp) -> timestamp
×
113
      _ -> default_start
×
114
    end
115
    
116
    end_time = case Keyword.get(opts, :until) do
×
117
      nil -> default_end
×
118
      %DateTime{} = dt -> DateTime.to_unix(dt, :millisecond)
×
119
      timestamp when is_integer(timestamp) -> timestamp
×
120
      _ -> default_end
×
121
    end
122
    
123
    {start_time, end_time}
124
  end
125
  
126
  defp apply_filters(events, opts) do
127
    events
128
    |> filter_by_pid(Keyword.get(opts, :pid))
129
    |> filter_by_event_type(Keyword.get(opts, :event_type))
130
    |> apply_limit(Keyword.get(opts, :limit))
×
131
  end
132
  
133
  defp filter_by_pid(events, nil), do: events
×
134
  defp filter_by_pid(events, :all), do: events
×
135
  defp filter_by_pid(events, target_pid) when is_pid(target_pid) do
136
    Enum.filter(events, fn event ->
×
137
      case Map.get(event, :pid) do
×
138
        ^target_pid -> true
×
139
        _ -> false
×
140
      end
141
    end)
142
  end
143
  
144
  defp filter_by_event_type(events, nil), do: events
×
145
  defp filter_by_event_type(events, :all), do: events
×
146
  defp filter_by_event_type(events, target_type) when is_atom(target_type) do
147
    Enum.filter(events, fn event ->
×
148
      case Map.get(event, :event_type) do
×
149
        ^target_type -> true
×
150
        _ -> false
×
151
      end
152
    end)
153
  end
154
  
155
  defp apply_limit(events, nil), do: events
×
156
  defp apply_limit(events, limit) when is_integer(limit) and limit > 0 do
157
    Enum.take(events, limit)
×
158
  end
159
  defp apply_limit(events, _), do: events
×
160
  
161
  defp get_default_event_store do
162
    # Try to find a running EventStore process
163
    # In test mode, look for test stores
164
    if Application.get_env(:elixir_scope, :test_mode, false) do
19✔
165
      # In test mode, try to find any test store
166
      case :ets.whereis(:test_api_store_events) do
14✔
167
        :undefined ->
168
          # Look for any test store
169
          case find_test_event_store() do
14✔
170
            nil -> {:error, :no_store}
×
171
            store -> {:ok, store}
14✔
172
          end
173
        _table ->
174
          # Found a test store, but we need the process
175
          case find_test_event_store() do
×
176
            nil -> {:error, :no_store}
×
177
            store -> {:ok, store}
×
178
          end
179
      end
180
    else
181
      # In production mode, look for the main EventStore
182
      case Process.whereis(EventStore) do
5✔
183
        nil -> {:error, :no_store}
5✔
184
        store -> {:ok, store}
×
185
      end
186
    end
187
  end
188
  
189
  defp find_test_event_store do
190
    # Find any running EventStore process for testing
191
    Process.list()
192
    |> Enum.find(fn pid ->
14✔
193
      case Process.info(pid, :dictionary) do
2,312✔
194
        {:dictionary, dict} ->
195
          case Keyword.get(dict, :"$initial_call") do
2,312✔
196
            {ElixirScope.Storage.EventStore, :init, 1} -> true
14✔
197
            _ -> false
2,298✔
198
          end
199
        _ -> false
×
200
      end
201
    end)
202
  end
203
  
204
  defp fallback_to_runtime_correlator(opts) do
205
    # Original RuntimeCorrelator logic as fallback
206
    case Process.whereis(RuntimeCorrelator) do
5✔
207
      nil ->
5✔
208
        {:error, :not_running}
209
      
210
      _pid ->
211
        try do
×
212
          case RuntimeCorrelator.health_check() do
×
213
            {:ok, %{status: :healthy}} ->
214
              {start_time, end_time} = extract_time_range(opts)
×
215
              
216
              case RuntimeCorrelator.query_temporal_events(start_time, end_time) do
×
217
                {:ok, events} ->
218
                  filtered_events = apply_filters(events, opts)
×
219
                  {:ok, filtered_events}
220
                
221
                {:error, _reason} ->
×
222
                  {:error, :runtime_correlator_error}
223
              end
224
            
225
            {:ok, %{status: _status}} ->
×
226
              {:error, :runtime_correlator_unhealthy}
227
            
228
            {:error, _reason} ->
×
229
              {:error, :runtime_correlator_error}
230
          end
231
        rescue
232
          _error -> {:error, :runtime_correlator_unavailable}
×
233
        end
234
    end
235
  end
236
end 
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc