1 |
|
-module(mongoose_log_filter). |
2 |
|
-export([fill_metadata_filter/2]). |
3 |
|
-export([format_c2s_state_filter/2]). |
4 |
|
-export([format_acc_filter/2]). |
5 |
|
-export([format_packet_filter/2]). |
6 |
|
-export([format_stacktrace_filter/2]). |
7 |
|
-export([format_term_filter/2]). |
8 |
|
-export([preserve_acc_filter/2]). |
9 |
|
-export([remove_fields_filter/2]). |
10 |
|
-export([filter_module/2]). |
11 |
|
|
12 |
|
-ignore_xref([filter_module/2, format_acc_filter/2, format_c2s_state_filter/2, |
13 |
|
format_packet_filter/2, format_stacktrace_filter/2, format_term_filter/2, |
14 |
|
preserve_acc_filter/2, remove_fields_filter/2]). |
15 |
|
|
16 |
|
-include("mongoose.hrl"). |
17 |
|
-include_lib("jid/include/jid.hrl"). |
18 |
|
-include("ejabberd_c2s.hrl"). |
19 |
|
|
20 |
|
%% The templater in flatlog works with meta fields. |
21 |
|
%% So, we would need a filter, that takes the interesting fields |
22 |
|
%% from msg to metadata. |
23 |
|
-spec fill_metadata_filter(logger:log_event(), term()) -> logger:filter_return(). |
24 |
|
fill_metadata_filter(Event=#{msg := {report, Msg}, meta := Meta}, Fields) -> |
25 |
18432 |
FieldMap = maps:with(Fields, Msg), |
26 |
|
%% Remove the fields to not print them twice |
27 |
18432 |
Msg2 = maps:without(Fields, Msg), |
28 |
18432 |
Event#{meta => maps:merge(FieldMap, Meta), msg => {report, Msg2}}; |
29 |
|
fill_metadata_filter(Event, _) -> |
30 |
578 |
Event. |
31 |
|
|
32 |
|
format_c2s_state_filter(Event=#{msg := {report, Msg=#{c2s_state := State}}}, _) -> |
33 |
218 |
StateMap = filter_undefined(c2s_state_to_map(State)), |
34 |
|
%% C2S fields have lower priority, if the field is already present in msg. |
35 |
218 |
Msg2 = maps:merge(StateMap, maps:remove(c2s_state, Msg)), |
36 |
218 |
Event#{msg => {report, Msg2}}; |
37 |
|
format_c2s_state_filter(Event, _) -> |
38 |
9287 |
Event. |
39 |
|
|
40 |
|
format_acc_filter(Event=#{msg := {report, Msg=#{acc := Acc}}}, _) -> |
41 |
1231 |
FormattedAcc = format_acc(Acc), |
42 |
1231 |
Msg2 = maps:merge(FormattedAcc, maps:remove(acc, Msg)), |
43 |
1231 |
Event#{msg => {report, Msg2}}; |
44 |
|
format_acc_filter(Event, _) -> |
45 |
8274 |
Event. |
46 |
|
|
47 |
|
%% Encodes exml_packet |
48 |
|
format_packet_filter(Event=#{msg := {report, Msg=#{exml_packet := Packet}}}, _) -> |
49 |
:-( |
BinPacket = exml:to_binary(Packet), |
50 |
:-( |
Msg2 = maps:put(packet, BinPacket, maps:remove(exml_packet, Msg)), |
51 |
:-( |
Event#{msg => {report, Msg2}}; |
52 |
|
format_packet_filter(Event, _) -> |
53 |
9505 |
Event. |
54 |
|
|
55 |
|
format_stacktrace_filter(Event=#{msg := {report, Msg=#{stacktrace := S}}}, _) -> |
56 |
61 |
FmtArgs = format_stacktrace_args(S), |
57 |
61 |
Msg2 = case FmtArgs of |
58 |
61 |
<<>> -> Msg; |
59 |
:-( |
_ -> Msg#{stacktrace_args => FmtArgs} |
60 |
|
end, |
61 |
61 |
Msg3 = case format_stacktrace(S) of |
62 |
8 |
<<>> -> Msg2; |
63 |
53 |
FmtStack -> Msg2#{stacktrace => FmtStack} |
64 |
|
end, |
65 |
61 |
Event#{msg => {report, Msg3 }}; |
66 |
|
format_stacktrace_filter(Event, _) -> |
67 |
9444 |
Event. |
68 |
|
|
69 |
|
format_term_filter(Event = #{msg := {report, Msg}}, Keys) -> |
70 |
9216 |
FormattedMsg = lists:foldl(fun format_value/2, Msg, Keys), |
71 |
9216 |
Event#{msg => {report, FormattedMsg}}; |
72 |
|
format_term_filter(Event, _) -> |
73 |
289 |
Event. |
74 |
|
|
75 |
|
format_value(Key, Msg) -> |
76 |
9216 |
case maps:find(Key, Msg) of |
77 |
:-( |
{ok, Value} -> Msg#{Key := format_term(Value)}; |
78 |
9216 |
error -> Msg |
79 |
|
end. |
80 |
|
|
81 |
|
format_acc(#{origin_pid := OriginPid, timestamp := TS, stanza := StanzaMap}) -> |
82 |
1230 |
Map = format_stanza_map(StanzaMap), |
83 |
1230 |
Map#{acc_timestamp => format_microseconds(TS), |
84 |
|
origin_pid => format_term(OriginPid)}; |
85 |
|
format_acc(_) -> |
86 |
1 |
#{}. |
87 |
|
|
88 |
|
format_stanza_map(#{element := Elem, from_jid := From, to_jid := To}) -> |
89 |
1230 |
#{packet => exml:to_binary(Elem), |
90 |
|
from_jid => jid:to_binary(From), |
91 |
|
to_jid => jid:to_binary(To)}; |
92 |
|
format_stanza_map(_) -> |
93 |
:-( |
#{}. |
94 |
|
|
95 |
|
preserve_acc_filter(Event=#{msg := {report, Msg=#{acc := Acc}}}, _) -> |
96 |
:-( |
Event#{msg => {report, Msg#{acc_original => format_term(Acc)}}}; |
97 |
|
preserve_acc_filter(Event, _) -> |
98 |
:-( |
Event. |
99 |
|
|
100 |
|
remove_fields_filter(Event=#{msg := {report, Msg=#{}}}, FieldNames) -> |
101 |
9216 |
Msg2 = maps:without(FieldNames, Msg), |
102 |
9216 |
Event#{msg => {report, Msg2}}; |
103 |
|
remove_fields_filter(Event, _) -> |
104 |
289 |
Event. |
105 |
|
|
106 |
|
|
107 |
|
c2s_state_to_map(#state{socket = Socket, streamid = StreamId, |
108 |
|
jid = Jid, sid = Sid}) -> |
109 |
218 |
SocketMap = ejabberd_socket:format_socket(Socket), |
110 |
218 |
SocketMap#{ |
111 |
|
streamid => StreamId, |
112 |
|
jid => maybe_jid_to_binary(Jid), |
113 |
|
user => maybe_jid_to_luser(Jid), |
114 |
|
server => maybe_jid_to_lserver(Jid), |
115 |
|
resource => maybe_jid_to_lresource(Jid), |
116 |
|
session_started => maybe_sid_to_timestamp(Sid)}. |
117 |
|
|
118 |
1230 |
format_term(X) -> iolist_to_binary(io_lib:format("~0p", [X])). |
119 |
|
|
120 |
218 |
maybe_jid_to_binary(Jid = #jid{}) -> jid:to_binary(Jid); |
121 |
:-( |
maybe_jid_to_binary(_) -> undefined. |
122 |
|
|
123 |
218 |
maybe_jid_to_luser(#jid{luser = LUser}) -> LUser; |
124 |
:-( |
maybe_jid_to_luser(_) -> undefined. |
125 |
|
|
126 |
218 |
maybe_jid_to_lserver(#jid{lserver = LServer}) -> LServer; |
127 |
:-( |
maybe_jid_to_lserver(_) -> undefined. |
128 |
|
|
129 |
218 |
maybe_jid_to_lresource(#jid{lresource = LResource}) -> LResource; |
130 |
:-( |
maybe_jid_to_lresource(_) -> undefined. |
131 |
|
|
132 |
217 |
maybe_sid_to_timestamp({Timestamp, _Pid}) -> format_microseconds(Timestamp); |
133 |
1 |
maybe_sid_to_timestamp(_) -> undefined. |
134 |
|
|
135 |
|
format_microseconds(N) -> |
136 |
1447 |
calendar:system_time_to_rfc3339(N, [{unit, microsecond}, |
137 |
|
{offset, 0}, |
138 |
|
{time_designator, $T}]). |
139 |
|
|
140 |
|
format_stacktrace_args([{_Mod,_Fun,Args,_Info}|_]) when is_list(Args) -> |
141 |
:-( |
iolist_to_binary(io_lib:format("~p", [Args])); |
142 |
|
format_stacktrace_args(_) -> |
143 |
61 |
<<>>. |
144 |
|
|
145 |
|
format_stacktrace(Stacktrace) -> |
146 |
61 |
iolist_to_binary(do_format_stacktrace(Stacktrace)). |
147 |
|
|
148 |
|
do_format_stacktrace([{Mod,Fun,Args,Info}|T]) when is_list(Args) -> |
149 |
:-( |
Arity = length(Args), |
150 |
:-( |
do_format_stacktrace([{Mod,Fun,Arity,Info}|T]); |
151 |
|
do_format_stacktrace([{Mod,Fun,Arity,Info}|T]) -> |
152 |
362 |
Line = proplists:get_value(line, Info, 0), |
153 |
362 |
H = io_lib:format("~p:~p/~p:~p", [Mod, Fun, Arity, Line]), |
154 |
362 |
more_format_stacktrace(H, T); |
155 |
|
do_format_stacktrace([Other|T]) -> |
156 |
:-( |
H = io_lib:format("~p", [Other]), |
157 |
:-( |
more_format_stacktrace(H, T); |
158 |
|
do_format_stacktrace([]) -> |
159 |
8 |
[]. |
160 |
|
|
161 |
|
more_format_stacktrace(H, []) -> |
162 |
53 |
[H]; |
163 |
|
more_format_stacktrace(H, T) -> |
164 |
309 |
[H, " "|do_format_stacktrace(T)]. |
165 |
|
|
166 |
|
filter_undefined(Map) -> |
167 |
218 |
maps:filter(fun(_, V) -> V =/= undefined end, Map). |
168 |
|
|
169 |
|
filter_module(Event = #{meta := #{mfa := {M,_,_}}}, Modules) when is_list(Modules) -> |
170 |
:-( |
case lists:member(M, Modules) of |
171 |
|
true -> |
172 |
:-( |
Event; |
173 |
|
false -> |
174 |
:-( |
stop |
175 |
|
end; |
176 |
|
filter_module(_Event, _Modules) -> |
177 |
:-( |
stop. %% module unknown, drop |