Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 668 lines (569 sloc) 18.966 kB
21abc5b @klacke Initial revision
authored
1 %%%----------------------------------------------------------------------
2 %%% File : yaws_debug.erl
3 %%% Author : Claes Wikstrom <klacke@hyber.org>
455578a @vinoski major trailing whitespace cleanup
vinoski authored
4 %%% Purpose :
21abc5b @klacke Initial revision
authored
5 %%% Created : 7 Feb 2002 by Claes Wikstrom <klacke@hyber.org>
6 %%%----------------------------------------------------------------------
7
8 -module(yaws_debug).
9 -author('klacke@hyber.org').
3c06a9e @klacke rearr of includefiles
authored
10
6cf3ece @klacke ""
authored
11 -include("../include/yaws.hrl").
12 -include("../include/yaws_api.hrl").
3c06a9e @klacke rearr of includefiles
authored
13 -include("yaws_debug.hrl").
9a74e5a @klacke Major general code cleanup, finally got rid of all the export_all sta…
authored
14 -export([typecheck/3,
15 format_record/3,
16 assert/4,
7334cee @klacke added gc/sc debug outputs for -d flag
authored
17 format/2,format/3,
9a74e5a @klacke Major general code cleanup, finally got rid of all the export_all sta…
authored
18 derror/2,
19 dinfo/2,
20 mktags/0,
21 xref/1,
22 pids/0,
23 eprof/0,
5207102 @klacke Added debug dump functionality
authored
24 check_headers/1, nobin/1,
25 do_debug_dump/1
26 ]).
6e96a14 @klacke indendation cleanup
authored
27
21abc5b @klacke Initial revision
authored
28
29
f44be6a @klacke all calls to old deprecated guard tests removed
authored
30 typecheck([{record, Rec, X} | Tail], File, Line) when is_atom(X),
0be3c7e @klacke untabified all of yaws
authored
31 element(1, Rec) == X ->
21abc5b @klacke Initial revision
authored
32 typecheck(Tail, File, Line);
f44be6a @klacke all calls to old deprecated guard tests removed
authored
33 typecheck([{int, Int} |Tail], File, Line) when is_integer(Int) ->
21abc5b @klacke Initial revision
authored
34 typecheck(Tail, File, Line);
35 typecheck([Err|_], File, Line) ->
0b3f29e @vinoski log debug messages to the error_logger for embedded mode (Nicolas Adiba)
vinoski authored
36 debug_format(user, "TC ERROR ~s:~w:~n~p",
0be3c7e @klacke untabified all of yaws
authored
37 [File, Line, Err]),
49cbf48 @klacke nice cleanup patch from Rickard Bucker
authored
38 erlang:error(tcerr);
21abc5b @klacke Initial revision
authored
39 typecheck([], _,_) ->
40 ok.
41
42
43 %% returns {record, RecName, [Field1, Val1} .....]
44 format_record(Record, Name, Fields) ->
45 case tuple_to_list(Record) of
0be3c7e @klacke untabified all of yaws
authored
46 [Name | Rest] ->
47 io_lib:format("record ~w\n~s", [Name,
48 format_record(Rest, Fields)]);
49 _X ->
50 ?Debug("Bad record ~p is not ~p~n", [_X, Name]),
51 "badrecord"
21abc5b @klacke Initial revision
authored
52 end.
53
54 format_record([], []) ->
55 [];
455578a @vinoski major trailing whitespace cleanup
vinoski authored
56 format_record([Val|Vals], [F|Fs]) when is_integer(Val);
57 Val == [];
f44be6a @klacke all calls to old deprecated guard tests removed
authored
58 is_atom(Val);
0be3c7e @klacke untabified all of yaws
authored
59 is_float(Val)->
bb9f1ff @klacke better looking debug printouts + dont overwrite trace_to_tty (-x comm…
authored
60 [io_lib:format(" ~w = ~w\n", [F,Val]),
61 format_record(Vals, Fs)];
21abc5b @klacke Initial revision
authored
62 format_record([Val|Vals], [F|Fs]) ->
bb9f1ff @klacke better looking debug printouts + dont overwrite trace_to_tty (-x comm…
authored
63 case is_string(Val) of
0be3c7e @klacke untabified all of yaws
authored
64 true ->
9a74e5a @klacke Major general code cleanup, finally got rid of all the export_all sta…
authored
65 [io_lib:format(" ~w = \"~s\"\n", [F,Val]),
0be3c7e @klacke untabified all of yaws
authored
66 format_record(Vals, Fs)];
67 false ->
68 [io_lib:format(" ~w = ~p~n", [F, nobin(Val)]),
69 format_record(Vals, Fs)]
bb9f1ff @klacke better looking debug printouts + dont overwrite trace_to_tty (-x comm…
authored
70 end.
21abc5b @klacke Initial revision
authored
71
f44be6a @klacke all calls to old deprecated guard tests removed
authored
72 is_string(L) when is_list(L) ->
73 lists:filter(fun(X) when is_integer(X),
0be3c7e @klacke untabified all of yaws
authored
74 $A < X, X < $z ->
75 false;
76 (_) ->
77 true
78 end,L) == [];
bb9f1ff @klacke better looking debug printouts + dont overwrite trace_to_tty (-x comm…
authored
79 is_string(_) ->
80 false.
0be3c7e @klacke untabified all of yaws
authored
81
21abc5b @klacke Initial revision
authored
82
83
84 assert(equal,X,Y,_) when X==Y ->
85 ok;
86 assert(neq,X,Y,_) when X/=Y ->
87 ok;
f44be6a @klacke all calls to old deprecated guard tests removed
authored
88 assert(integer,X,_,_) when is_integer(X) ->
21abc5b @klacke Initial revision
authored
89 ok;
f44be6a @klacke all calls to old deprecated guard tests removed
authored
90 assert(list,X,_,_) when is_list(X) ->
21abc5b @klacke Initial revision
authored
91 ok;
f44be6a @klacke all calls to old deprecated guard tests removed
authored
92 assert({list,length,equal},X,Y,_) when is_list(X), length(X)==Y ->
21abc5b @klacke Initial revision
authored
93 ok;
f44be6a @klacke all calls to old deprecated guard tests removed
authored
94 assert(greater,X,Y,_) when is_integer(X), is_integer(Y), X>Y ->
21abc5b @klacke Initial revision
authored
95 ok;
f44be6a @klacke all calls to old deprecated guard tests removed
authored
96 assert(min,X,Y,_) when is_integer(X), is_integer(Y), X>=Y ->
21abc5b @klacke Initial revision
authored
97 ok;
f44be6a @klacke all calls to old deprecated guard tests removed
authored
98 assert(lesser,X,Y,_) when is_integer(X), is_integer(Y), X<Y ->
21abc5b @klacke Initial revision
authored
99 ok;
f44be6a @klacke all calls to old deprecated guard tests removed
authored
100 assert(max,X,Y,_) when is_integer(X), is_integer(Y), X=<Y ->
21abc5b @klacke Initial revision
authored
101 ok;
455578a @vinoski major trailing whitespace cleanup
vinoski authored
102 assert(interval,X,{Min,Max},_) when is_integer(X), is_integer(Min),
103 is_integer(Max),
f44be6a @klacke all calls to old deprecated guard tests removed
authored
104 X>=Min, Max>=X ->
21abc5b @klacke Initial revision
authored
105 ok;
106 assert('fun', Fun, _, Failure) ->
107 case catch Fun() of
0be3c7e @klacke untabified all of yaws
authored
108 true -> ok;
109 _Other -> fail(Failure)
21abc5b @klacke Initial revision
authored
110 end;
111
f44be6a @klacke all calls to old deprecated guard tests removed
authored
112 assert(in,X,L,Failure) when is_list(L) ->
21abc5b @klacke Initial revision
authored
113 case lists:member(X,L) of
0be3c7e @klacke untabified all of yaws
authored
114 true -> ok;
115 _ -> fail(Failure)
21abc5b @klacke Initial revision
authored
116 end;
117
118 assert(_,_,_,Failure) ->
119 fail(Failure).
120
121 fail({assert,File,Line,Message}) ->
0b3f29e @vinoski log debug messages to the error_logger for embedded mode (Nicolas Adiba)
vinoski authored
122 debug_format(user, "Assertion FAILED ~p:~p, pid ~w exiting: ~p~n",
0be3c7e @klacke untabified all of yaws
authored
123 [File, Line, self(), Message]),
49cbf48 @klacke nice cleanup patch from Rickard Bucker
authored
124 erlang:error(assertion_failed);
21abc5b @klacke Initial revision
authored
125 fail({alert,File,Line,Message}) ->
0b3f29e @vinoski log debug messages to the error_logger for embedded mode (Nicolas Adiba)
vinoski authored
126 debug_format(user, "Assert WARNING ~p:~p, pid ~w: ~p~n",
0be3c7e @klacke untabified all of yaws
authored
127 [File, Line, self(), Message]),
21abc5b @klacke Initial revision
authored
128 ok;
129 fail({{debug,Fstr}, File,Line,Fmt, Args}) ->
130 Str = lists:flatten(
0be3c7e @klacke untabified all of yaws
authored
131 io_lib:format("~s <~p> ~s:~p, pid ~w: ~n",
455578a @vinoski major trailing whitespace cleanup
vinoski authored
132 [Fstr, node(), filename:basename(File),
0be3c7e @klacke untabified all of yaws
authored
133 Line, self()])),
134
0b3f29e @vinoski log debug messages to the error_logger for embedded mode (Nicolas Adiba)
vinoski authored
135 case (catch debug_format(user, Str ++ Fmt ++ "~n", Args)) of
0be3c7e @klacke untabified all of yaws
authored
136 ok -> ok;
0b3f29e @vinoski log debug messages to the error_logger for embedded mode (Nicolas Adiba)
vinoski authored
137 _ -> debug_format(user, "ERROR ~p:~p: Pid ~w: (bad format)~n~p,~p~n",
0be3c7e @klacke untabified all of yaws
authored
138 [File, Line, self(), Fmt, Args]),
139
140 ok
21abc5b @klacke Initial revision
authored
141 end;
142
143 fail({format, File,Line,Fmt,Args}) ->
0b3f29e @vinoski log debug messages to the error_logger for embedded mode (Nicolas Adiba)
vinoski authored
144 case (catch debug_format(user, Fmt,Args)) of
0be3c7e @klacke untabified all of yaws
authored
145 ok -> ok;
146 _ ->
0b3f29e @vinoski log debug messages to the error_logger for embedded mode (Nicolas Adiba)
vinoski authored
147 debug_format(user, "ERROR ~p:~p: Pid ~w: (bad format)~n~p,~p~n",
0be3c7e @klacke untabified all of yaws
authored
148 [File, Line, self(), Fmt, Args]),
149
150 ok
21abc5b @klacke Initial revision
authored
151 end.
152
0b3f29e @vinoski log debug messages to the error_logger for embedded mode (Nicolas Adiba)
vinoski authored
153 debug_format(_, F, D) ->
154 debug_format(F, D).
155
156 debug_format(F, A) ->
157 Str = case catch io_lib:format("yaws debug: " ++ F, A) of
158 {'EXIT', Reason} ->
159 io_lib:format("yaws debug: F=~s A=~p (failed to format: ~p)",
160 [F, A, Reason]);
161 Ok -> Ok
162 end,
163 error_logger:info_msg(Str),
164 catch io:format(F, A),
165 ok.
166
7334cee @klacke added gc/sc debug outputs for -d flag
authored
167 format(F, A) ->
168 format(get(gc), F, A).
169 format(GC, F, A) ->
170 case ?gc_has_debug(GC) of
0be3c7e @klacke untabified all of yaws
authored
171 true ->
0b3f29e @vinoski log debug messages to the error_logger for embedded mode (Nicolas Adiba)
vinoski authored
172 error_logger:info_msg("yaws debug:" ++ F, A);
0be3c7e @klacke untabified all of yaws
authored
173 false ->
174 ok
ef3a52a @klacke Removed the atoms in parse_post and parse query, backwards incompatib…
authored
175 end.
961926f @klacke ""
authored
176
ef3a52a @klacke Removed the atoms in parse_post and parse query, backwards incompatib…
authored
177 derror(F, A) ->
178 case ?gc_has_debug((get(gc))) of
0be3c7e @klacke untabified all of yaws
authored
179 true ->
180 error_logger:error_msg("yaws:" ++ F, A);
181 false ->
182 ok
ef3a52a @klacke Removed the atoms in parse_post and parse query, backwards incompatib…
authored
183 end.
961926f @klacke ""
authored
184
ef3a52a @klacke Removed the atoms in parse_post and parse query, backwards incompatib…
authored
185 dinfo(F, A) ->
186 case ?gc_has_debug((get(gc))) of
0be3c7e @klacke untabified all of yaws
authored
187 true ->
188 error_logger:info_msg("yaws:" ++ F, A);
189 false ->
190 ok
ef3a52a @klacke Removed the atoms in parse_post and parse query, backwards incompatib…
authored
191 end.
f0341a3 @klacke ""
authored
192
193
0d623c1 @klacke ""
authored
194 mktags() ->
195 tags:dirs(["."]),
196 init:stop().
197
198
199
200 xref([Dir]) ->
0b3f29e @vinoski log debug messages to the error_logger for embedded mode (Nicolas Adiba)
vinoski authored
201 debug_format("~p~n", [xref:d(Dir)]),
0d623c1 @klacke ""
authored
202 init:stop().
203
204
205 pids() ->
206 lists:zf(
207 fun(P) ->
0be3c7e @klacke untabified all of yaws
authored
208 case process_info(P) of
f44be6a @klacke all calls to old deprecated guard tests removed
authored
209 L when is_list(L) ->
455578a @vinoski major trailing whitespace cleanup
vinoski authored
210 {value, {_, {M1, _,_}}} =
0be3c7e @klacke untabified all of yaws
authored
211 lists:keysearch(current_function, 1, L),
455578a @vinoski major trailing whitespace cleanup
vinoski authored
212 {value, {_, {M2, _,_}}} =
0be3c7e @klacke untabified all of yaws
authored
213 lists:keysearch(initial_call, 1, L),
214 S1= atom_to_list(M1),
215 S2 = atom_to_list(M2),
216 case {S1, S2} of
217 {"yaws" ++ _, _} ->
218 {true, P};
219 {_, "yaws"++_} ->
220 {true, P};
221 _ ->
222 false
223 end;
224 _ ->
225 false
226 end
0d623c1 @klacke ""
authored
227 end,
228 processes()).
229
0be3c7e @klacke untabified all of yaws
authored
230
0d623c1 @klacke ""
authored
231
232 eprof() ->
233 eprof:start(),
234 eprof:profile(pids()),
0b3f29e @vinoski log debug messages to the error_logger for embedded mode (Nicolas Adiba)
vinoski authored
235 debug_format("Ok run some traffic \n", []).
0be3c7e @klacke untabified all of yaws
authored
236
0d623c1 @klacke ""
authored
237
8d5aa60 @klacke ""
authored
238
ffee7fc @klacke some more debug support
authored
239 -define(h_check(H, Field),
0be3c7e @klacke untabified all of yaws
authored
240 f_check(H#outh.Field, Field)).
ffee7fc @klacke some more debug support
authored
241
242 f_check(undefined, _Field) ->
243 ok;
244 f_check(Str, Field) ->
245 case lists:reverse(lists:flatten(Str)) of
0be3c7e @klacke untabified all of yaws
authored
246 [$\n, $\r , H | _Tail] ->
247 case lists:member(H, [$\n, $\r]) of
248 true ->
249 error_logger:format("Bad <~p> header:~n"
250 " ~p~nToo many newlines",
251 [Field, Str]),
252 exit(normal);
253 false ->
254 ok
255 end;
256 _Other ->
257 error_logger:format("Bad <~p> header:~n"
258 "~p~nNot ending with CRNL~n",
259 [Field, Str]),
260 exit(normal)
ffee7fc @klacke some more debug support
authored
261 end.
262
263 check_headers(H) ->
264 ?h_check(H, connection),
265 ?h_check(H, server),
266 ?h_check(H, location),
267 ?h_check(H, cache_control),
268 ?h_check(H, date),
269 ?h_check(H, allow),
270 ?h_check(H, last_modified),
271 ?h_check(H, etag),
272 ?h_check(H, content_range),
273 ?h_check(H, content_length),
274 ?h_check(H, content_encoding),
275 ?h_check(H, set_cookie),
276 ?h_check(H, transfer_encoding),
277 ?h_check(H, www_authenticate),
278 check_other(H#outh.other).
279
280
281 check_other(undefined) ->
282 ok;
283 check_other(L0) ->
284 L = lists:flatten(L0),
285 case lists:dropwhile(fun(X) -> not lists:member(X, ["\r\n"]) end, L) of
0be3c7e @klacke untabified all of yaws
authored
286 [] ->
287 ok;
288 [$\r, $\n, H | _Tail] ->
289 case lists:member(H, [$\n, $\r]) of
290 true ->
291 bad_other(L);
292 false ->
293 ok
294 end;
295 _Other ->
296 bad_other(L)
ffee7fc @klacke some more debug support
authored
297 end.
298
299
300 bad_other(L) ->
0be3c7e @klacke untabified all of yaws
authored
301 Bad = lists:takewhile(
302 fun(X) -> not lists:member(X, ["\r\n"]) end, L),
ffee7fc @klacke some more debug support
authored
303 error_logger:format("Bad header:~p~n"
0be3c7e @klacke untabified all of yaws
authored
304 "Too many newlines",
305 [Bad]),
ffee7fc @klacke some more debug support
authored
306 exit(normal).
8d5aa60 @klacke ""
authored
307
308
309
e8dfbc2 @klacke ""
authored
310
00303e2 @klacke outh record, the outgoing headers are built up into a record now, muc…
authored
311 nobin(X) ->
312 case catch xnobin(X) of
0be3c7e @klacke untabified all of yaws
authored
313 {'EXIT', Reason} ->
314 error_logger:format("~p~n~p~n", [X, Reason]),
315 erlang:error(Reason);
316 Res ->
317 Res
00303e2 @klacke outh record, the outgoing headers are built up into a record now, muc…
authored
318 end.
e8dfbc2 @klacke ""
authored
319
00303e2 @klacke outh record, the outgoing headers are built up into a record now, muc…
authored
320
f44be6a @klacke all calls to old deprecated guard tests removed
authored
321 xnobin(B) when is_binary(B) ->
e8dfbc2 @klacke ""
authored
322 lists:flatten(io_lib:format("#Bin(~w)", [size(B)]));
f44be6a @klacke all calls to old deprecated guard tests removed
authored
323 xnobin(L) when is_list(L) ->
00303e2 @klacke outh record, the outgoing headers are built up into a record now, muc…
authored
324 lists:map(fun(X) -> xnobin(X) end, L);
f44be6a @klacke all calls to old deprecated guard tests removed
authored
325 xnobin(T) when is_tuple(T) ->
00303e2 @klacke outh record, the outgoing headers are built up into a record now, muc…
authored
326 list_to_tuple(xnobin(tuple_to_list(T)));
327 xnobin(X) ->
e8dfbc2 @klacke ""
authored
328 X.
5207102 @klacke Added debug dump functionality
authored
329
330
331
332 %%%%%%%%%%%%%%% debug dump %%%%%%%%%%%%%%%%%%%%%%%
333
334
335 do_debug_dump(Socket) ->
336 gen_version(Socket),
337 gen_sep(Socket),
338 %% keep proc status last, to report on hangs for the others
455578a @vinoski major trailing whitespace cleanup
vinoski authored
339 CollectOS = gen_os(Socket),
5207102 @klacke Added debug dump functionality
authored
340 Collect = lists:foldl(fun({F, Str}, Acc) ->
341 Ret = collect(F, Socket, Str),
342 gen_sep(Socket),
343 [Ret|Acc]
344 end,
345 CollectOS,
346 [{fun send_status/1, "Yaws status"},
347 {fun send_inet/1, "Inet status"},
348 {proc_status_fun(), "process status"}]),
349 lists:foreach(fun(ok) ->
350 ok;
351 ({pid, Pid}) ->
352 exit(Pid, shutdown)
353 end, Collect),
354 ok.
355
356
357 gen_version(Socket) ->
358 sock_format(Socket, "Yawsvsn: ~p~n", [yaws_generated:version()]).
359
360 gen_os(Socket) ->
361 OSType = os:type(),
362 [gen_oscmd(Socket, "uname -a"),
363 gen_oscmd(Socket, "ifconfig -a"),
364 gen_oscmd(Socket, top_cmd(OSType)),
365 gen_oscmd(Socket, netstat_cmd(OSType))].
366
455578a @vinoski major trailing whitespace cleanup
vinoski authored
367 gen_oscmd(Socket, Cmd) ->
5207102 @klacke Added debug dump functionality
authored
368 F = fun(Sock) ->
369 sock_format(Sock, "~s:~n~s~n", [Cmd, os:cmd(Cmd)])
370 end,
371 Ret = collect(F, Socket, Cmd),
372 gen_sep(Socket),
373 Ret.
374
375 %% FIXME The 'top -b -n 1' invocation is actually for version 3.2.x
376 %% typically(?) found on Linux, while the 'top -b' is for (e.g.) version
377 %% 3.5.x typically(?) found on *BSD. For the latter, '-b' itself means
378 %% "run only once", '-n' is an alias for '-b', and '1' means show only
379 %% one process. Obviously there is a problem if 3.2.x or equivalent ends
380 %% up getting invoked w/o '-n 1', since it will loop forever...
381 top_cmd({unix, linux}) -> "top -b -n 1";
382 top_cmd({unix, sunos}) -> "top -b -d 2 -s 1 || /usr/ucb/ps -auxww";
383 top_cmd({unix, qnx}) -> "pidin times; pidin pmem";
384 top_cmd({unix, darwin}) -> "top -o cpu -l 1";
385 top_cmd(_) -> "top -b".
386
387 netstat_cmd({unix, linux}) -> "netstat -ant";
388 netstat_cmd({unix, freebsd}) -> "netstat -an -p tcp";
389 netstat_cmd({unix, sunos}) -> "netstat -an -P tcp";
390 netstat_cmd(_) -> "netstat -an".
6e96a14 @klacke indendation cleanup
authored
391
455578a @vinoski major trailing whitespace cleanup
vinoski authored
392 gen_sep(Socket) ->
5207102 @klacke Added debug dump functionality
authored
393 sock_format(Socket,"~n~s~n", [lists:duplicate(40, $*)]).
6e96a14 @klacke indendation cleanup
authored
394
5207102 @klacke Added debug dump functionality
authored
395
396 proc_status_fun() ->
397 fun(Fd) ->
398 sock_format(Fd, "Process status:~n", []),
399 i1(Fd, processes())
400 end.
401
402 i1(Fd, Ps) ->
403 Alive = lists:filter(fun palive/1, Ps),
404 i2(Fd, Alive),
405 case lists:filter(fun pzombie/1, Ps) of
406 [] ->
407 ok;
408 Zombies ->
409 %% Zombies is not the same as Ps-Alive, since the remote
410 %% process that fetched Ps is included among Alive, but has
411 %% exited (for ni/0).
412 sock_format(Fd, "\nDead processes:\n", []),
413 i2(Fd, Zombies)
414 end.
415
416 i2(Fd, Ps) ->
417 iformat(Fd, "Pid", "Initial Call", "Current Function", "Reds", "Msgs",
418 "Heap", "Stack"),
419 {Reds,Msgs,Heap,Stack,Susp1,Susp2,MemSusp,_} =
420 lists:foldl(fun display_info/2, {0,0,0,0,[],[],[],Fd}, Ps),
421 iformat(Fd, "Total", "", "", io_lib:write(Reds), io_lib:write(Msgs),
6e96a14 @klacke indendation cleanup
authored
422 io_lib:write(Heap), io_lib:write(Stack)),
5207102 @klacke Added debug dump functionality
authored
423 lists:foreach(fun(Susp) -> display_susp1(Fd, Susp) end, Susp1),
424 lists:foreach(fun(Susp) -> display_susp2(Fd, Susp) end, Susp2),
425 lists:foreach(fun(Susp) -> display_susp3(Fd, Susp) end, MemSusp).
426
427
428 palive(Pid) ->
429 case process_info(Pid, status) of
430 undefined -> false;
431 {status, exiting} -> false;
432 _ -> true
433 end.
434
435 pzombie(Pid) ->
436 case process_info(Pid, status) of
437 undefined -> false;
438 {status, exiting} -> true;
439 _ -> false
440 end.
441
442
443 -define(MEM_LARGE, 40000).
444
445 display_info(Pid, {R,M,H,St,S1,S2,S3,Fd}) ->
446 case process_info(Pid) of
447 undefined ->
448 {R, M};
449 Info ->
450 Call = initial_call(Info),
451 Curr = fetch(current_function, Info),
452 Reds = fetch(reductions, Info),
453 LM = fetch(message_queue_len, Info),
454 Heap = fetch(heap_size, Info),
455 Stack = fetch(stack_size, Info),
456 Mem = case process_info(Pid, memory) of
8e64d3b @klacke Some minor bugs, and some dead code removed, all found by Tuncers run…
authored
457 undefined -> 0;
5207102 @klacke Added debug dump functionality
authored
458 {memory, Int} -> Int
459 end,
460 iformat(Fd,
461 io_lib:write(Pid),
462 mfa_string(Call),
463 mfa_string(Curr),
464 io_lib:write(Reds),
465 io_lib:write(LM),
466 io_lib:write(Heap),
467 io_lib:write(Stack)),
468 %% if it got msgs, it's suspicios
469 NS1 = if LM > 0 -> [{Pid, Reds, LM} | S1];
470 true -> S1
471 end,
472 %% if it's in gen:wait_resp* it's suspicios
473 NS2 = case Curr of
474 {gen, wait_resp, _} -> [{Pid, Reds} | S2];
475 {gen, wait_resp_mon, _} -> [{Pid, Reds} | S2];
476 _ -> S2
477 end,
478 %% If it is large .. it is suspicios
479 NS3 = if Mem > ?MEM_LARGE ->
480 [{Pid, Mem} | S3];
481 true ->
482 S3
483 end,
484 {R+Reds, M+LM, H+Heap,St+Stack, NS1, NS2, NS3, Fd}
485 end.
486
487 display_susp1(Fd, {Pid, Reds0, LM0}) ->
488 case process_info(Pid) of
489 undefined ->
490 ok;
491 Info ->
492 Reds1 = fetch(reductions, Info),
493 LM1 = fetch(message_queue_len, Info),
494 Msgs = fetch(messages, Info),
495 Bt = case process_info(Pid, backtrace) of
496 {backtrace, Bin} ->
497 binary_to_list(Bin);
498 _ ->
499 []
500 end,
501 if LM1 > 0 ->
502 %% still suspicious
503 sock_format(Fd,
6e96a14 @klacke indendation cleanup
authored
504 "*** Suspicious *** : ~-12w, Qlen = ~4w/~-4w, "
505 "Reds = ~12w/~-12w\n",
506 [Pid, LM0, LM1, Reds0, Reds1]),
5207102 @klacke Added debug dump functionality
authored
507 lists:foreach(
508 fun(Msg) -> sock_format(Fd, " ~p\n",[Msg]) end,
509 Msgs),
510 gen_sep(Fd),
511 sock_format(Fd, "\n\n\n\n*** Backtrace *** for ~w\n~s\n",
6e96a14 @klacke indendation cleanup
authored
512 [Pid,Bt]);
5207102 @klacke Added debug dump functionality
authored
513 true ->
514 ok
515 end
516 end.
517
518 display_susp2(Fd, {Pid, Reds0}) ->
519 case process_info(Pid, reductions) of
520 undefined ->
521 ok;
522 {reductions, Reds0} ->
523 %% it hasn't done any work... print bt
524 case process_info(Pid, backtrace) of
525 {backtrace, Bin} ->
526 gen_sep(Fd),
527 sock_format(Fd, "\n\n\n\n*** Backtrace (gen_wait) "
528 "*** for ~w\n~s\n",
529 [Pid, binary_to_list(Bin)]);
530 _ ->
531 ok
532 end;
533 _ ->
534 ok
535 end.
536
537 display_susp3(Fd, {Pid, _Mem}) ->
538 case {process_info(Pid, memory), process_info(Pid, current_function)} of
539 {undefined, _} ->
540 ok;
541 {_, {current_function,{yaws_debug,display_susp3,2}}} ->
542 ok;
8e64d3b @klacke Some minor bugs, and some dead code removed, all found by Tuncers run…
authored
543 {{memory, Mem2}, _} when Mem2 > ?MEM_LARGE ->
5207102 @klacke Added debug dump functionality
authored
544 %% it's still too big
545 case process_info(Pid, backtrace) of
546 {backtrace, Bin} ->
547 gen_sep(Fd),
455578a @vinoski major trailing whitespace cleanup
vinoski authored
548 sock_format(Fd,
5207102 @klacke Added debug dump functionality
authored
549 "\n\n\n\n*** Backtrace (mem=~p) "
550 "*** for ~w\n~p~n~s\n",
551 [Mem2, Pid, process_info(Pid),
552 binary_to_list(Bin)]);
553 _ ->
554 ok
555 end;
556 _ ->
557 ok
558 end.
559
560
561
562 initial_call(Info) ->
563 case fetch(initial_call, Info) of
564 {proc_lib, init_p, 5} ->
565 proc_lib:translate_initial_call(Info);
566 ICall ->
567 ICall
568 end.
569
570 mfa_string({M, F, A}) ->
571 io_lib:format("~w:~w/~w", [M, F, A]);
572 mfa_string(X) ->
573 io_lib:write(X).
574
575 fetch(Key, Info) ->
576 case lists:keysearch(Key, 1, Info) of
577 {value, {_, Val}} -> Val;
578 false -> 0
579 end.
580
581 iformat(Fd, A1, A2, A3, A4, A5, A6, A7) ->
582 sock_format(Fd, "~-12s ~-23s ~-23s ~12s ~4s ~12s ~10s\n",
583 [A1,A2,A3,A4,A5,A6,A7]).
584
585 sock_format(Sock, Fmt, Args) ->
586 gen_tcp:send(Sock, io_lib:format(Fmt, Args)).
587
588 -define(COLLECT_TIMEOUT, 10000).
589
590
591 %% purpose of this collect function is to not hang, remember a probable
592 %% reason for running debug-dump is that the system is in a
593 %% corrupt state.
594
595 collect(F, Sock, User) ->
596 SELF = self(),
597 Pid = spawn(fun() ->
598 F(Sock),
599 SELF ! {self(), ok},
600 timer:sleep(infinity)
601 end),
602 Ref = erlang:monitor(process, Pid),
603 receive
604 {Pid, ok} ->
605 erlang:demonitor(Ref),
606 exit(Pid, shutdown),
607 ok;
608 Down = {'DOWN', Ref, _,_,_} ->
609 sock_format(Sock, "*** Failed to collect ~s: ~p~n", [User, Down]),
610 ok
611 after ?COLLECT_TIMEOUT ->
612 erlang:demonitor(Ref),
613 sock_format(Sock, "*** Failed to collect ~s: timeout~n", [User]),
614 {pid, Pid} % Let it hang for proc status, exit after
615 end.
6e96a14 @klacke indendation cleanup
authored
616
5207102 @klacke Added debug dump functionality
authored
617 send_status(Sock) ->
618 {InitStatus, _} = init:get_status(),
619 sock_format(Sock, ["vsn: ", yaws_generated:version(), "\n"], []),
620 sock_format(Sock, "status: ~p\n", [InitStatus]),
621 ok.
622
623 send_inet(Sock) ->
624 Chars = capture_io(fun() -> inet:i() end),
625 sock_format(Sock, "inet:i() output ~n~s~n", [Chars]),
626 ok.
627
628
629 %% This function runs a Fun that is producing IO through
455578a @vinoski major trailing whitespace cleanup
vinoski authored
630 %% io:format() and collects the IO and retuns the IO as a char list
5207102 @klacke Added debug dump functionality
authored
631 %% Returns io_list() | {timeout, io_list()}
632 %%
633 capture_io(Fun) ->
634 do_capture_io(Fun).
ca1c8b1 @karlsson Fixed a number of compiler warnings and html validation errors
karlsson authored
635
636 %% capture_io(Fun, MilliSecTimeout) ->
637 %% {ok, Tref} = timer:send_after(MilliSecTimeout, capio_timeout),
638 %% Chars = do_capture_io(Fun),
639 %% timer:cancel(Tref),
640 %% Chars.
6e96a14 @klacke indendation cleanup
authored
641
5207102 @klacke Added debug dump functionality
authored
642 do_capture_io(Fun) ->
455578a @vinoski major trailing whitespace cleanup
vinoski authored
643 Pid = spawn(fun() ->
5207102 @klacke Added debug dump functionality
authored
644 receive run -> ok end,
645 Fun()
646 end),
647 Mref = erlang:monitor(process,Pid),
648 group_leader(self(), Pid),
649 Pid ! run,
650 collect_io(Pid, Mref, []).
651
652 collect_io(Pid, Mref, Ack) ->
653 receive
654 {'DOWN', Mref, _,_,_} ->
655 Ack;
656 {io_request, From, Me, {put_chars, M, F, A}} ->
657 From ! {io_reply, Me, ok},
658 collect_io(Pid, Mref, [Ack, apply(M,F, A)]);
659 capio_timeout ->
660 {timeout, Ack}
661 end.
662
663
6e96a14 @klacke indendation cleanup
authored
664
665
5207102 @klacke Added debug dump functionality
authored
666
667
Something went wrong with that request. Please try again.