Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

239 řádky
9.0 KiB

před 13 roky
  1. %% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved.
  2. %%
  3. %% This file is provided to you under the Apache License,
  4. %% Version 2.0 (the "License"); you may not use this file
  5. %% except in compliance with the License. You may obtain
  6. %% a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing,
  11. %% software distributed under the License is distributed on an
  12. %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  13. %% KIND, either express or implied. See the License for the
  14. %% specific language governing permissions and limitations
  15. %% under the License.
  16. -module(lager_default_formatter).
  17. %%
  18. %% Include files
  19. %%
  20. -include("lager.hrl").
  21. -ifdef(TEST).
  22. -include_lib("eunit/include/eunit.hrl").
  23. -endif.
  24. %%
  25. %% Exported Functions
  26. %%
  27. -export([format/2, format/3]).
  28. %%
  29. %% API Functions
  30. %%
  31. %% @doc Provides a generic, default formatting for log messages using a semi-iolist as configuration. Any iolist allowed
  32. %% elements in the configuration are printed verbatim. Atoms in the configuration are treated as metadata properties
  33. %% and extracted from the log message. Optionally, a tuple of {atom(),semi-iolist()} can be used. The atom will look
  34. %% up the property, but if not found it will use the semi-iolist() instead. These fallbacks can be similarly nested
  35. %% or refer to other properties, if desired. You can also use a {atom, semi-iolist(), semi-iolist()} formatter, which
  36. %% acts like a ternary operator's true/false branches.
  37. %%
  38. %% The metadata properties date,time, message, and severity will always exist.
  39. %% The properties pid, file, line, module, and function will always exist if the parser transform is used.
  40. %%
  41. %% Example:
  42. %%
  43. %% `["Foo"]' -> "Foo", regardless of message content.
  44. %%
  45. %% `[message]' -> The content of the logged message, alone.
  46. %%
  47. %% `[{pid,"Unknown Pid"}]' -> "?.?.?" if pid is in the metadata, "Unknown Pid" if not.
  48. %%
  49. %% `[{pid, ["My pid is ", pid], ["Unknown Pid"]}]' -> if pid is in the metada print "My pid is ?.?.?", otherwise print "Unknown Pid"
  50. %% @end
  51. -spec format(lager_msg:lager_msg(),list(),list()) -> any().
  52. format(Msg,[], Colors) ->
  53. format(Msg, [{eol, "\n"}], Colors);
  54. format(Msg,[{eol, EOL}], Colors) ->
  55. format(Msg,
  56. [date, " ", time, " ", color, "[", severity, "] ",
  57. {pid, ""},
  58. {module, [
  59. {pid, ["@"], ""},
  60. module,
  61. {function, [":", function], ""},
  62. {line, [":",line], ""}], ""},
  63. " ", message, EOL], Colors);
  64. format(Message,Config,Colors) ->
  65. [ case V of
  66. color -> output_color(Message,Colors);
  67. _ -> output(V,Message)
  68. end || V <- Config ].
  69. -spec format(lager_msg:lager_msg(),list()) -> any().
  70. format(Msg, Config) ->
  71. format(Msg, Config, []).
  72. -spec output(term(),lager_msg:lager_msg()) -> iolist().
  73. output(message,Msg) -> lager_msg:message(Msg);
  74. output(date,Msg) ->
  75. {D, _T} = lager_msg:datetime(Msg),
  76. D;
  77. output(time,Msg) ->
  78. {_D, T} = lager_msg:datetime(Msg),
  79. T;
  80. output(severity,Msg) ->
  81. atom_to_list(lager_msg:severity(Msg));
  82. output(Prop,Msg) when is_atom(Prop) ->
  83. Metadata = lager_msg:metadata(Msg),
  84. make_printable(get_metadata(Prop,Metadata,<<"Undefined">>));
  85. output({Prop,Default},Msg) when is_atom(Prop) ->
  86. Metadata = lager_msg:metadata(Msg),
  87. make_printable(get_metadata(Prop,Metadata,output(Default,Msg)));
  88. output({Prop, Present, Absent}, Msg) when is_atom(Prop) ->
  89. %% sort of like a poor man's ternary operator
  90. Metadata = lager_msg:metadata(Msg),
  91. case get_metadata(Prop, Metadata) of
  92. undefined ->
  93. [ output(V, Msg) || V <- Absent];
  94. _ ->
  95. [ output(V, Msg) || V <- Present]
  96. end;
  97. output(Other,_) -> make_printable(Other).
  98. output_color(_Msg,[]) -> [];
  99. output_color(Msg,Colors) ->
  100. Level = lager_msg:severity(Msg),
  101. case lists:keyfind(Level, 1, Colors) of
  102. {_, Color} -> Color;
  103. _ -> []
  104. end.
  105. -spec make_printable(any()) -> iolist().
  106. make_printable(A) when is_atom(A) -> atom_to_list(A);
  107. make_printable(P) when is_pid(P) -> pid_to_list(P);
  108. make_printable(L) when is_list(L) orelse is_binary(L) -> L;
  109. make_printable(Other) -> io_lib:format("~p",[Other]).
  110. get_metadata(Key, Metadata) ->
  111. get_metadata(Key, Metadata, undefined).
  112. get_metadata(Key, Metadata, Default) ->
  113. case lists:keyfind(Key, 1, Metadata) of
  114. false ->
  115. Default;
  116. {Key, Value} ->
  117. Value
  118. end.
  119. -ifdef(TEST).
  120. date_time_now() ->
  121. Now = os:timestamp(),
  122. {Date, Time} = lager_util:format_time(lager_util:maybe_utc(lager_util:localtime_ms(Now))),
  123. {Date, Time, Now}.
  124. basic_test_() ->
  125. {Date, Time, Now} = date_time_now(),
  126. [{"Default formatting test",
  127. ?_assertEqual(iolist_to_binary([Date, " ", Time, " [error] ", pid_to_list(self()), " Message\n"]),
  128. iolist_to_binary(format(lager_msg:new("Message",
  129. Now,
  130. error,
  131. [{pid, self()}],
  132. []),
  133. [])))
  134. },
  135. {"Basic Formatting",
  136. ?_assertEqual(<<"Simplist Format">>,
  137. iolist_to_binary(format(lager_msg:new("Message",
  138. Now,
  139. error,
  140. [{pid, self()}],
  141. []),
  142. ["Simplist Format"])))
  143. },
  144. {"Default equivalent formatting test",
  145. ?_assertEqual(iolist_to_binary([Date, " ", Time, " [error] ", pid_to_list(self()), " Message\n"]),
  146. iolist_to_binary(format(lager_msg:new("Message",
  147. Now,
  148. error,
  149. [{pid, self()}],
  150. []),
  151. [date, " ", time," [",severity,"] ",pid, " ", message, "\n"]
  152. )))
  153. },
  154. {"Non existant metadata can default to string",
  155. ?_assertEqual(iolist_to_binary([Date, " ", Time, " [error] Fallback Message\n"]),
  156. iolist_to_binary(format(lager_msg:new("Message",
  157. Now,
  158. error,
  159. [{pid, self()}],
  160. []),
  161. [date, " ", time," [",severity,"] ",{does_not_exist,"Fallback"}, " ", message, "\n"]
  162. )))
  163. },
  164. {"Non existant metadata can default to other metadata",
  165. ?_assertEqual(iolist_to_binary([Date, " ", Time, " [error] Fallback Message\n"]),
  166. iolist_to_binary(format(lager_msg:new("Message",
  167. Now,
  168. error,
  169. [{pid, "Fallback"}],
  170. []),
  171. [date, " ", time," [",severity,"] ",{does_not_exist,pid}, " ", message, "\n"]
  172. )))
  173. },
  174. {"Non existant metadata can default to a string2",
  175. ?_assertEqual(iolist_to_binary(["Unknown Pid"]),
  176. iolist_to_binary(format(lager_msg:new("Message",
  177. Now,
  178. error,
  179. [],
  180. []),
  181. [{pid, ["My pid is ", pid], ["Unknown Pid"]}]
  182. )))
  183. },
  184. {"Metadata can have extra formatting",
  185. ?_assertEqual(iolist_to_binary(["My pid is hello"]),
  186. iolist_to_binary(format(lager_msg:new("Message",
  187. Now,
  188. error,
  189. [{pid, hello}],
  190. []),
  191. [{pid, ["My pid is ", pid], ["Unknown Pid"]}]
  192. )))
  193. },
  194. {"Metadata can have extra formatting1",
  195. ?_assertEqual(iolist_to_binary(["servername"]),
  196. iolist_to_binary(format(lager_msg:new("Message",
  197. Now,
  198. error,
  199. [{pid, hello}, {server, servername}],
  200. []),
  201. [{server,{pid, ["(", pid, ")"], ["(Unknown Server)"]}}]
  202. )))
  203. },
  204. {"Metadata can have extra formatting2",
  205. ?_assertEqual(iolist_to_binary(["(hello)"]),
  206. iolist_to_binary(format(lager_msg:new("Message",
  207. Now,
  208. error,
  209. [{pid, hello}],
  210. []),
  211. [{server,{pid, ["(", pid, ")"], ["(Unknown Server)"]}}]
  212. )))
  213. },
  214. {"Metadata can have extra formatting3",
  215. ?_assertEqual(iolist_to_binary(["(Unknown Server)"]),
  216. iolist_to_binary(format(lager_msg:new("Message",
  217. Now,
  218. error,
  219. [],
  220. []),
  221. [{server,{pid, ["(", pid, ")"], ["(Unknown Server)"]}}]
  222. )))
  223. }
  224. ].
  225. -endif.