1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(sasl_report).
21
22-export([write_report/3, format_report/3]).
23
24format_report(Fd, What, Report) ->
25    io_report(io_lib, Fd, What, Report).
26
27write_report(Fd, What, Report) ->
28    io_report(io, Fd, What, Report).
29
30io_report(IO, Fd, What, {Time, {error_report, _GL, {Pid, Type, Report}}}) ->
31    case is_my_error_report(What, Type) of
32	true ->
33	    Head = write_head(Type, Time, Pid),
34	    write_report2(IO, Fd, Head, Type, Report);
35	_ -> true
36    end;
37io_report(IO, Fd, What, {Time, {info_report, _GL, {Pid, Type, Report}}}) ->
38    case is_my_info_report(What, Type) of
39	true ->
40	    Head = write_head(Type, Time, Pid),
41	    write_report2(IO, Fd, Head, Type, Report);
42	_ -> true
43    end;
44io_report(_IO, _Fd, _, _) ->
45    false.
46
47is_my_error_report(all, Type)   ->  is_my_error_report(Type);
48is_my_error_report(error, Type) ->  is_my_error_report(Type);
49is_my_error_report(_, _Type)    ->  false.
50
51is_my_error_report(supervisor_report)   -> true;
52is_my_error_report(crash_report)        -> true;
53is_my_error_report(_)                   -> false.
54
55is_my_info_report(all, Type)      -> is_my_info_report(Type);
56is_my_info_report(progress, Type) -> is_my_info_report(Type);
57is_my_info_report(_, _Type)       -> false.
58
59is_my_info_report(progress)  -> true;
60is_my_info_report(_)                    -> false.
61
62write_report2(IO, Fd, Head, supervisor_report, Report) ->
63    Name = sup_get(supervisor, Report),
64    Context = sup_get(errorContext, Report),
65    Reason = sup_get(reason, Report),
66    Offender = sup_get(offender, Report),
67    Enc = encoding(Fd),
68    {FmtString,Args} = supervisor_format([Name,Context,Reason,Offender], Enc),
69    String = io_lib:format(FmtString, Args),
70    write_report_action(IO, Fd, Head, String);
71write_report2(IO, Fd, Head, progress, Report) ->
72    Encoding = encoding(Fd),
73    Depth = error_logger:get_format_depth(),
74    String = format_key_val(Report, Encoding, Depth),
75    write_report_action(IO, Fd, Head, String);
76write_report2(IO, Fd, Head, crash_report, Report) ->
77    Encoding = encoding(Fd),
78    Depth = error_logger:get_format_depth(),
79    String = proc_lib:format(Report, Encoding, Depth),
80    write_report_action(IO, Fd, Head, String).
81
82supervisor_format(Args0, Encoding) ->
83    {P, Tl} = p(Encoding, error_logger:get_format_depth()),
84    [A,B,C,D] = Args0,
85    Args = [A|Tl] ++ [B|Tl] ++ [C|Tl] ++ [D|Tl],
86    {"     Supervisor: ~" ++ P ++ "\n"
87     "     Context:    ~" ++ P ++ "\n"
88     "     Reason:     ~80.18" ++ P ++ "\n"
89     "     Offender:   ~80.18" ++ P ++ "\n~n",
90     Args}.
91
92write_report_action(IO, Fd, Head, String) ->
93    S = [Head|String],
94    case IO of
95	io -> io:put_chars(Fd, S);
96	io_lib -> S
97    end.
98
99format_key_val(Rep, Encoding, Depth) ->
100    {P, Tl} = p(Encoding, Depth),
101    format_key_val1(Rep, P, Tl).
102
103format_key_val1([{Tag,Data}|Rep], P, Tl) ->
104    (io_lib:format("    ~16w: ~" ++ P ++ "\n", [Tag, Data|Tl]) ++
105     format_key_val1(Rep, P, Tl));
106format_key_val1(_, _, _) ->
107    [].
108
109p(Encoding, Depth) ->
110    {Letter, Tl}  = case Depth of
111                        unlimited -> {"p", []};
112                        _         -> {"P", [Depth]}
113                    end,
114    P = modifier(Encoding) ++ Letter,
115    {P, Tl}.
116
117encoding(IO) ->
118    case lists:keyfind(encoding, 1, io:getopts(IO)) of
119	false -> latin1;
120	{encoding, Enc} -> Enc
121    end.
122
123modifier(latin1) -> "";
124modifier(_) -> "t".
125
126sup_get(Tag, Report) ->
127    case lists:keysearch(Tag, 1, Report) of
128	{value, {_, Value}} ->
129	    Value;
130	_ ->
131	    ""
132    end.
133
134maybe_utc(Time) ->
135    case application:get_env(sasl,utc_log) of
136	{ok,true} ->
137	    case calendar:local_time_to_universal_time_dst(Time) of
138		[UTC] ->
139		    {utc,UTC};
140		[UTC1,_UTC2] ->
141		    {utc,UTC1};
142		[] -> % should not happen
143		    Time
144	    end;
145	_ ->
146	    Time
147    end.
148
149write_head(supervisor_report, Time, Pid) ->
150    write_head1("SUPERVISOR REPORT", maybe_utc(Time), Pid);
151write_head(crash_report, Time, Pid) ->
152    write_head1("CRASH REPORT", maybe_utc(Time), Pid);
153write_head(progress, Time, Pid) ->
154    write_head1("PROGRESS REPORT", maybe_utc(Time), Pid).
155
156write_head1(Type, {utc,{{Y,Mo,D},{H,Mi,S}}}, Pid) when node(Pid) /= node() ->
157    io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC (~p) ===~n",
158		  [Type,D,month(Mo),Y,t(H),t(Mi),t(S),node(Pid)]);
159write_head1(Type, {utc,{{Y,Mo,D},{H,Mi,S}}}, _) ->
160    io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n",
161		  [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]);
162write_head1(Type, {{Y,Mo,D},{H,Mi,S}}, Pid) when node(Pid) /= node() ->
163    io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s (~p) ===~n",
164		  [Type,D,month(Mo),Y,t(H),t(Mi),t(S),node(Pid)]);
165write_head1(Type, {{Y,Mo,D},{H,Mi,S}}, _) ->
166    io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s ===~n",
167		  [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]).
168
169t(X) when is_integer(X) ->
170    t1(integer_to_list(X));
171t(_) ->
172    "".
173t1([X]) -> [$0,X];
174t1(X)   -> X.
175
176month(1) -> "Jan";
177month(2) -> "Feb";
178month(3) -> "Mar";
179month(4) -> "Apr";
180month(5) -> "May";
181month(6) -> "Jun";
182month(7) -> "Jul";
183month(8) -> "Aug";
184month(9) -> "Sep";
185month(10) -> "Oct";
186month(11) -> "Nov";
187month(12) -> "Dec".
188