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