/** * Copyright © 2016 IBM Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include namespace phosphor { namespace logging { /** @enum level * @brief Enum for priority level */ enum class level { EMERG = LOG_EMERG, ALERT = LOG_ALERT, CRIT = LOG_CRIT, ERR = LOG_ERR, WARNING = LOG_WARNING, NOTICE = LOG_NOTICE, INFO = LOG_INFO, DEBUG = LOG_DEBUG, }; namespace details { /** @fn prio() * @brief Prepend PRIORITY= to the input priority string. * This is required by sd_journal_send(). * @tparam L - Priority level */ template constexpr auto prio() { constexpr const char* prio_str = "PRIORITY=%d"; constexpr const auto prio_tuple = std::make_tuple(prio_str, L); return prio_tuple; } /** @fn helper_log() * @brief Helper function for details::log(). Log request to journal. * @tparam T - Type of tuple * @tparam I - std::integer_sequence of indexes (0..N) for each tuple element * @param[in] e - Tuple containing the data to be logged * @param[unnamed] - std::integer_sequence of tuple's index values */ template void helper_log(T&& e, std::integer_sequence) { // https://www.freedesktop.org/software/systemd/man/sd_journal_print.html // TODO: Re-enable call through interface for testing (or move the code // into the body of the object). sd_journal_send(std::get(std::forward(e))..., NULL); } /** @fn details::log() * @brief Implementation of logging::log() function. * Send request msg and size to helper funct to log it to the journal. * @tparam T - Type of tuple * @param[in] e - Tuple containing the data to be logged */ template void log(T&& e) { constexpr auto e_size = std::tuple_size>::value; helper_log(std::forward(e), std::make_index_sequence{}); } } // namespace details template struct is_char_ptr_argtype : std::integral_constant< bool, (std::is_pointer::type>::value && std::is_same::type>::type>::type, char>::value)> { }; template struct is_printf_argtype : std::integral_constant< bool, (std::is_integral::type>::value || std::is_enum::type>::value || std::is_floating_point< typename std::remove_reference::type>::value || std::is_pointer::type>::value)> { }; template struct bool_pack; template using all_true = std::is_same, bool_pack>; /** @fn entry() * @brief Pack each format string entry as a tuple to be able to validate * the string and parameters when multiple entries are passed to be logged. * @tparam Arg - Types of first argument * @tparam Args - Types of remaining arguments * @param[in] arg - First metadata string of form VAR=value where * VAR is the variable name in uppercase and * value is of any size and format * @param[in] args - Remaining metadata strings */ template constexpr auto entry(Arg&& arg, Args&&... args) { static_assert(is_char_ptr_argtype::value, "bad argument type: use char*"); static_assert(all_true::value...>::value, "bad argument type: use string.c_str() if needed"); return std::make_tuple(std::forward(arg), std::forward(args)...); } /** @fn log() * @brief Log message to systemd journal * @tparam L - Priority level * @param[in] msg - Message to be logged in C-string format * @param[in] entry - Metadata fields to be added to the message * @details Usage: log(const char*, entry(*format), entry()...); * @example log( * "Simple Example"); * char msg_str[] = "File not found"; * log( * msg_str, * entry("MY_METADATA=%s_%x, name, number)); */ template void log(Msg msg, Entry... e) { static_assert((std::is_same>::value || std::is_same>::value), "First parameter must be a C-string."); constexpr const char* msg_str = "MESSAGE=%s"; const auto msg_tuple = std::make_tuple(msg_str, std::forward(msg)); constexpr auto transactionStr = "TRANSACTION_ID=%lld"; auto transactionId = sdbusplus::server::transaction::get_id(); auto log_tuple = std::tuple_cat(details::prio(), msg_tuple, entry(transactionStr, transactionId), std::forward(e)...); details::log(log_tuple); } } // namespace logging } // namespace phosphor