1%% This Source Code Form is subject to the terms of the Mozilla Public 2%% License, v. 2.0. If a copy of the MPL was not distributed with this 3%% file, You can obtain one at https://mozilla.org/MPL/2.0/. 4%% 5%% Copyright (c) 2021 VMware, Inc. or its affiliates. All rights reserved. 6%% 7 8-module(rabbit_logger_fmt_helpers). 9 10-export([format_time/2, 11 format_level/2, 12 format_msg/3]). 13 14format_time(Timestamp, #{time_format := Format}) -> 15 format_time1(Timestamp, Format); 16format_time(Timestamp, _) -> 17 format_time1(Timestamp, {rfc3339, $\s, ""}). 18 19format_time1(Timestamp, {rfc3339, Sep, Offset}) -> 20 Options = [{unit, microsecond}, 21 {offset, Offset}, 22 {time_designator, Sep}], 23 calendar:system_time_to_rfc3339(Timestamp, Options); 24format_time1(Timestamp, {epoch, secs, int}) -> 25 Timestamp div 1000000; 26format_time1(Timestamp, {epoch, usecs, int}) -> 27 Timestamp; 28format_time1(Timestamp, {epoch, secs, binary}) -> 29 io_lib:format("~.6.0f", [Timestamp / 1000000]); 30format_time1(Timestamp, {epoch, usecs, binary}) -> 31 io_lib:format("~b", [Timestamp]); 32format_time1(Timestamp, {LocalOrUniversal, Format, Args}) -> 33 %% The format string and the args list is prepared by 34 %% `rabbit_prelaunch_early_logging:translate_generic_conf()'. 35 {{Year, Month, Day}, 36 {Hour, Minute, Second}} = case LocalOrUniversal of 37 local -> 38 calendar:system_time_to_local_time( 39 Timestamp, microsecond); 40 universal -> 41 calendar:system_time_to_universal_time( 42 Timestamp, microsecond) 43 end, 44 Args1 = lists:map( 45 fun 46 (year) -> Year; 47 (month) -> Month; 48 (day) -> Day; 49 (hour) -> Hour; 50 (minute) -> Minute; 51 (second) -> Second; 52 ({second_fractional, 53 Decimals}) -> second_fractional(Timestamp, Decimals) 54 end, Args), 55 io_lib:format(Format, Args1). 56 57second_fractional(Timestamp, Decimals) -> 58 (Timestamp rem 1000000) div (1000000 div round(math:pow(10, Decimals))). 59 60format_level(Level, Config) -> 61 format_level1(Level, Config). 62 63format_level1(Level, #{level_format := lc}) -> 64 level_lc_name(Level); 65format_level1(Level, #{level_format := uc}) -> 66 level_uc_name(Level); 67format_level1(Level, #{level_format := lc3}) -> 68 level_3letter_lc_name(Level); 69format_level1(Level, #{level_format := uc3}) -> 70 level_3letter_uc_name(Level); 71format_level1(Level, #{level_format := lc4}) -> 72 level_4letter_lc_name(Level); 73format_level1(Level, #{level_format := uc4}) -> 74 level_4letter_uc_name(Level); 75format_level1(Level, _) -> 76 level_4letter_lc_name(Level). 77 78level_lc_name(debug) -> "debug"; 79level_lc_name(info) -> "info"; 80level_lc_name(notice) -> "notice"; 81level_lc_name(warning) -> "warning"; 82level_lc_name(error) -> "error"; 83level_lc_name(critical) -> "critical"; 84level_lc_name(alert) -> "alert"; 85level_lc_name(emergency) -> "emergency". 86 87level_uc_name(debug) -> "DEBUG"; 88level_uc_name(info) -> "INFO"; 89level_uc_name(notice) -> "NOTICE"; 90level_uc_name(warning) -> "WARNING"; 91level_uc_name(error) -> "ERROR"; 92level_uc_name(critical) -> "CRITICAL"; 93level_uc_name(alert) -> "ALERT"; 94level_uc_name(emergency) -> "EMERGENCY". 95 96level_3letter_lc_name(debug) -> "dbg"; 97level_3letter_lc_name(info) -> "inf"; 98level_3letter_lc_name(notice) -> "ntc"; 99level_3letter_lc_name(warning) -> "wrn"; 100level_3letter_lc_name(error) -> "err"; 101level_3letter_lc_name(critical) -> "crt"; 102level_3letter_lc_name(alert) -> "alt"; 103level_3letter_lc_name(emergency) -> "emg". 104 105level_3letter_uc_name(debug) -> "DBG"; 106level_3letter_uc_name(info) -> "INF"; 107level_3letter_uc_name(notice) -> "NTC"; 108level_3letter_uc_name(warning) -> "WRN"; 109level_3letter_uc_name(error) -> "ERR"; 110level_3letter_uc_name(critical) -> "CRT"; 111level_3letter_uc_name(alert) -> "ALT"; 112level_3letter_uc_name(emergency) -> "EMG". 113 114level_4letter_lc_name(debug) -> "dbug"; 115level_4letter_lc_name(info) -> "info"; 116level_4letter_lc_name(notice) -> "noti"; 117level_4letter_lc_name(warning) -> "warn"; 118level_4letter_lc_name(error) -> "erro"; 119level_4letter_lc_name(critical) -> "crit"; 120level_4letter_lc_name(alert) -> "alrt"; 121level_4letter_lc_name(emergency) -> "emgc". 122 123level_4letter_uc_name(debug) -> "DBUG"; 124level_4letter_uc_name(info) -> "INFO"; 125level_4letter_uc_name(notice) -> "NOTI"; 126level_4letter_uc_name(warning) -> "WARN"; 127level_4letter_uc_name(error) -> "ERRO"; 128level_4letter_uc_name(critical) -> "CRIT"; 129level_4letter_uc_name(alert) -> "ALRT"; 130level_4letter_uc_name(emergency) -> "EMGC". 131 132format_msg(Msg, Meta, #{single_line := true} = Config) -> 133 FormattedMsg = format_msg1(Msg, Meta, Config), 134 %% The following behavior is the same as the one in the official 135 %% `logger_formatter'; the code is taken from that module (as of 136 %% c5ed910098e9c2787e2c3f9f462c84322064e00d in the master branch). 137 FormattedMsg1 = string:strip(FormattedMsg, both), 138 re:replace( 139 FormattedMsg1, 140 ",?\r?\n\s*", 141 ", ", 142 [{return, list}, global, unicode]); 143format_msg(Msg, Meta, Config) -> 144 format_msg1(Msg, Meta, Config). 145 146format_msg1({string, Chardata}, Meta, Config) -> 147 format_msg1({"~ts", [Chardata]}, Meta, Config); 148format_msg1({report, Report}, Meta, Config) -> 149 FormattedReport = format_report(Report, Meta, Config), 150 format_msg1(FormattedReport, Meta, Config); 151format_msg1({Format, Args}, _, _) -> 152 io_lib:format(Format, Args). 153 154format_report( 155 #{label := {application_controller, _}} = Report, Meta, Config) -> 156 format_application_progress(Report, Meta, Config); 157format_report( 158 #{label := {supervisor, progress}} = Report, Meta, Config) -> 159 format_supervisor_progress(Report, Meta, Config); 160format_report( 161 Report, #{report_cb := Cb} = Meta, Config) -> 162 try 163 case erlang:fun_info(Cb, arity) of 164 {arity, 1} -> Cb(Report); 165 {arity, 2} -> {"~ts", [Cb(Report, #{})]} 166 end 167 catch 168 _:_:_ -> 169 format_report(Report, maps:remove(report_cb, Meta), Config) 170 end; 171format_report(Report, _, _) -> 172 logger:format_report(Report). 173 174format_application_progress(#{label := {_, progress}, 175 report := InternalReport}, _, _) -> 176 Application = proplists:get_value(application, InternalReport), 177 StartedAt = proplists:get_value(started_at, InternalReport), 178 {"Application ~w started on ~0p", 179 [Application, StartedAt]}; 180format_application_progress(#{label := {_, exit}, 181 report := InternalReport}, _, _) -> 182 Application = proplists:get_value(application, InternalReport), 183 Exited = proplists:get_value(exited, InternalReport), 184 {"Application ~w exited with reason: ~0p", 185 [Application, Exited]}. 186 187format_supervisor_progress(#{report := InternalReport}, _, _) -> 188 Supervisor = proplists:get_value(supervisor, InternalReport), 189 Started = proplists:get_value(started, InternalReport), 190 Id = proplists:get_value(id, Started), 191 Pid = proplists:get_value(pid, Started), 192 Mfa = proplists:get_value(mfargs, Started), 193 {"Supervisor ~w: child ~w started (~w): ~0p", 194 [Supervisor, Id, Pid, Mfa]}. 195