@@ -3,25 +3,33 @@ defmodule Matcha.Trace.Handler do
33 About trace handlers.
44 """
55
6+ @ default_width 120
7+
68 alias Matcha.Trace
79
10+ import Inspect.Algebra
11+
812 use GenServer
913
10- defstruct [ :trace , :caller , :io_device ]
14+ defstruct [ :trace , :caller , :io_device , :width , :worker_supervisor ]
1115
1216 @ type t :: % __MODULE__ {
1317 trace: Trace . t ( ) ,
1418 caller: pid ( ) | nil ,
15- io_device: IO . device ( )
19+ io_device: IO . device ( ) ,
20+ width: non_neg_integer ( ) | :infinity ,
21+ worker_supervisor: pid ( )
1622 }
1723
1824 def options ( options \\ [ ] ) do
1925 { caller , options } = Keyword . pop ( options , :caller , self ( ) )
2026 { io_device , options } = Keyword . pop ( options , :io_device , Process . group_leader ( ) )
27+ { width , options } = Keyword . pop ( options , :width , @ default_width )
2128
2229 { [
2330 caller: caller ,
24- io_device: io_device
31+ io_device: io_device ,
32+ width: width
2533 ] , options }
2634 end
2735
@@ -86,6 +94,9 @@ defmodule Matcha.Trace.Handler do
8694 Process . link ( handler . caller )
8795 end
8896
97+ { :ok , worker_supervisor } = Trace.Supervisor . start_worker_supervisor ( handler , [ ] )
98+ handler = % __MODULE__ { handler | worker_supervisor: worker_supervisor }
99+
89100 { :ok , handler }
90101 end
91102
@@ -102,20 +113,87 @@ defmodule Matcha.Trace.Handler do
102113 @ impl true
103114 def handle_cast ( message , handler )
104115
105- # Invoke user-defined handler function when available
106- def handle_cast (
107- { :__matcha_trace__ , message } ,
108- handler = % __MODULE__ { trace: % Trace { handler: fun } }
109- )
110- when not is_nil ( fun ) do
111- fun . ( handler , message )
116+ def handle_cast ( { :__matcha_trace__ , message } , handler = % __MODULE__ { trace: % Trace { handler: custom_handler } } ) do
117+ worker = if custom_handler do
118+ fn ->
119+ custom_handler . ( handler , message )
120+ end
121+ else
122+ fn ->
123+ IO . puts ( handler . io_device , format_message ( handler , message ) )
124+ end
125+ end
126+
127+ Task.Supervisor . start_child ( handler . worker_supervisor , worker )
128+
112129 { :noreply , handler }
113130 end
114131
115- # Otherwise, by default write back to IO device
116- def handle_cast ( { :__matcha_trace__ , message } , handler = % __MODULE__ { } ) do
117- IO . puts ( handler . io_device , Trace . format_message ( message ) )
132+ @ spec format_message ( % __MODULE__ { } , Trace . message ( ) ) :: iodata ( )
133+ @ doc """
134+ Formats a trace message.
135+ """
136+ def format_message ( handler , message )
118137
119- { :noreply , handler }
138+ def format_message ( handler , { :trace , pid , :call , { module , function , arguments } } ) do
139+ call = format_call ( module , function , arguments , pid )
140+
141+ "Matcha.Trace:"
142+ |> Inspect.Algebra . glue ( call )
143+ |> Inspect.Algebra . nest ( 2 )
144+ |> Inspect.Algebra . format ( handler . width )
145+ end
146+
147+ def format_message ( handler , { :trace , pid , :call , { module , function , arguments } , message } ) do
148+ call = format_call ( module , function , arguments , pid , message )
149+
150+ "Matcha.Trace:"
151+ |> Inspect.Algebra . glue ( call )
152+ |> Inspect.Algebra . nest ( 2 )
153+ |> Inspect.Algebra . format ( handler . width )
154+ end
155+
156+ def format_message ( handler , term ) do
157+ # "Matcha.Trace:"
158+ # |> Inspect.Algebra.glue("unrecognized trace message:")
159+ # # |> Inspect.Algebra.
160+ # |> Inspect.Algebra.nest(2)
161+ "Matcha.Trace: unrecognized trace message\n ```\n #{ inspect ( term ) } \n ```\n "
162+ end
163+
164+ defp format_call ( module , function , arguments , pid , message \\ nil )
165+
166+ defp format_call ( module , function , arguments , pid , message ) when is_list ( arguments ) do
167+ arity = length ( arguments )
168+ call = call_to_string ( module , function , arity )
169+
170+ " traced call `#{ call } `" <>
171+ "\n on pid: #{ inspect ( pid ) } " <>
172+ if message do
173+ "\n with message: #{ message } "
174+ else
175+ ""
176+ end <>
177+ "\n with arguments:\n ```\n #{ inspect ( arguments ) } \n ```"
178+ end
179+
180+ defp format_call ( module , function , arity , pid , message ) when is_integer ( arity ) do
181+ call = call_to_string ( module , function , arity )
182+
183+ "\n traced call `#{ call } `" <>
184+ "\n on pid: #{ inspect ( pid ) } " <>
185+ if message do
186+ "\n with message: #{ message } "
187+ else
188+ ""
189+ end
190+ end
191+
192+ defp format_arguments ( arguments ) do
193+
194+ end
195+
196+ defp call_to_string ( module , function , arity ) when is_integer ( arity ) do
197+ Macro . to_string ( quote ( do: & ( unquote ( module ) . unquote ( function ) / unquote ( arity ) ) ) )
120198 end
121199end
0 commit comments