| /** |
| * 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 <systemd/sd-journal.h> |
| |
| #include <phosphor-logging/sdjournal.hpp> |
| #include <sdbusplus/server/transaction.hpp> |
| #include <tuple> |
| #include <type_traits> |
| |
| 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 <level L> |
| 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 <typename T, size_t... I> |
| void helper_log(T&& e, std::integer_sequence<size_t, I...>) |
| { |
| // 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<I>(std::forward<T>(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 <typename T> |
| void log(T&& e) |
| { |
| constexpr auto e_size = std::tuple_size<std::decay_t<T>>::value; |
| helper_log(std::forward<T>(e), std::make_index_sequence<e_size>{}); |
| } |
| |
| } // namespace details |
| |
| template <class T> |
| struct is_char_ptr_argtype |
| : std::integral_constant< |
| bool, |
| (std::is_pointer<typename std::decay<T>::type>::value && |
| std::is_same<typename std::remove_cv<typename std::remove_pointer< |
| typename std::decay<T>::type>::type>::type, |
| char>::value)> |
| { |
| }; |
| |
| template <class T> |
| struct is_printf_argtype |
| : std::integral_constant< |
| bool, |
| (std::is_integral<typename std::remove_reference<T>::type>::value || |
| std::is_enum<typename std::remove_reference<T>::type>::value || |
| std::is_floating_point< |
| typename std::remove_reference<T>::type>::value || |
| std::is_pointer<typename std::decay<T>::type>::value)> |
| { |
| }; |
| |
| template <bool...> |
| struct bool_pack; |
| |
| template <bool... bs> |
| using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>; |
| |
| /** @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 <typename Arg, typename... Args> |
| constexpr auto entry(Arg&& arg, Args&&... args) |
| { |
| static_assert(is_char_ptr_argtype<Arg>::value, |
| "bad argument type: use char*"); |
| static_assert(all_true<is_printf_argtype<Args>::value...>::value, |
| "bad argument type: use string.c_str() if needed"); |
| return std::make_tuple(std::forward<Arg>(arg), std::forward<Args>(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<level::XX>(const char*, entry(*format), entry()...); |
| * @example log<level::DEBUG>( |
| * "Simple Example"); |
| * char msg_str[] = "File not found"; |
| * log<level::DEBUG>( |
| * msg_str, |
| * entry("MY_METADATA=%s_%x, name, number)); |
| */ |
| template <level L, typename Msg, typename... Entry> |
| void log(Msg msg, Entry... e) |
| { |
| static_assert((std::is_same<const char*, std::decay_t<Msg>>::value || |
| std::is_same<char*, std::decay_t<Msg>>::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>(msg)); |
| |
| constexpr auto transactionStr = "TRANSACTION_ID=%llu"; |
| auto transactionId = sdbusplus::server::transaction::get_id(); |
| |
| auto log_tuple = std::tuple_cat(details::prio<L>(), msg_tuple, |
| entry(transactionStr, transactionId), |
| std::forward<Entry>(e)...); |
| details::log(log_tuple); |
| } |
| |
| } // namespace logging |
| |
| } // namespace phosphor |