blob: a933591b3ce13e19403d1b078c44defc43d09973 [file] [log] [blame]
Adriana Kobylak91da4532016-07-20 12:42:55 -05001/**
2 * Copyright © 2016 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain 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, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <tuple>
Joseph Reynolds8f6f7fc2018-05-04 10:11:00 -050020#include <type_traits>
Adriana Kobylak91da4532016-07-20 12:42:55 -050021#include <systemd/sd-journal.h>
Adriana Kobylak7d0692a2016-12-06 15:13:23 -060022#include <sdbusplus/server/transaction.hpp>
Adriana Kobylak91da4532016-07-20 12:42:55 -050023
24namespace phosphor
25{
26
27namespace logging
28{
29
30/** @enum level
31 * @brief Enum for priority level
32 */
33enum class level
34{
35 EMERG = LOG_EMERG,
36 ALERT = LOG_ALERT,
37 CRIT = LOG_CRIT,
38 ERR = LOG_ERR,
39 WARNING = LOG_WARNING,
40 NOTICE = LOG_NOTICE,
41 INFO = LOG_INFO,
42 DEBUG = LOG_DEBUG,
43};
44
45/** @fn log()
46 * @brief Log message to systemd journal
47 * @tparam L - Priority level
48 * @param[in] msg - Message to be logged in C-string format
49 * @param[in] entry - Metadata fields to be added to the message
50 * @details Usage: log<level::XX>(const char*, entry(*format), entry()...);
51 * @example log<level::DEBUG>(
52 * "Simple Example");
53 * char msg_str[] = "File not found";
54 * log<level::DEBUG>(
55 * msg_str,
56 * entry("MY_METADATA=%s_%x, name, number));
57 */
58template <level L, typename Msg, typename ...Entry>
59void log(Msg msg, Entry... entry);
60
61/** @fn entry()
62 * @brief Pack each format string entry as a tuple to be able to validate
63 * the string and parameters when multiple entries are passed to be logged.
64 * @tparam Arg - Types of first argument
65 * @tparam Args - Types of remaining arguments
66 * @param[in] arg - First metadata string of form VAR=value where
67 * VAR is the variable name in uppercase and
68 * value is of any size and format
69 * @param[in] args - Remaining metadata strings
70 */
71template <typename Arg, typename ...Args>
72constexpr auto entry(Arg&& arg, Args&&... args);
73
74namespace details
75{
76
77/** @fn prio()
78 * @brief Prepend PRIORITY= to the input priority string.
79 * This is required by sd_journal_send().
80 * @tparam L - Priority level
81 */
82template <level L>
83constexpr auto prio()
84{
85 constexpr const char *prio_str = "PRIORITY=%d";
86 constexpr const auto prio_tuple = std::make_tuple(prio_str, L);
87 return prio_tuple;
88}
89
90/** @fn helper_log()
91 * @brief Helper function for details::log(). Log request to journal.
92 * @tparam T - Type of tuple
93 * @tparam I - std::integer_sequence of indexes (0..N) for each tuple element
94 * @param[in] e - Tuple containing the data to be logged
95 * @param[unnamed] - std::integer_sequence of tuple's index values
96 */
97template <typename T, size_t ...I>
98void helper_log(T&& e, std::integer_sequence<size_t, I...>)
99{
Andrew Geissler328889d2016-10-10 12:43:48 -0500100 // https://www.freedesktop.org/software/systemd/man/sd_journal_print.html
Adriana Kobylak91da4532016-07-20 12:42:55 -0500101 sd_journal_send(std::get<I>(std::forward<T>(e))..., NULL);
102}
103
104/** @fn details::log()
105 * @brief Implementation of logging::log() function.
106 * Send request msg and size to helper funct to log it to the journal.
107 * @tparam T - Type of tuple
108 * @param[in] e - Tuple containing the data to be logged
109 */
110template <typename T>
111void log(T&& e)
112{
113 constexpr auto e_size = std::tuple_size<std::decay_t<T>>::value;
114 helper_log(std::forward<T>(e), std::make_index_sequence<e_size>{});
115}
116
117} // namespace details
118
119template <level L, typename Msg, typename ...Entry>
Adriana Kobylak7d0692a2016-12-06 15:13:23 -0600120void log(Msg msg, Entry... e)
Adriana Kobylak91da4532016-07-20 12:42:55 -0500121{
122 static_assert((std::is_same<const char*, std::decay_t<Msg>>::value ||
123 std::is_same<char*, std::decay_t<Msg>>::value),
124 "First parameter must be a C-string.");
125
126 constexpr const char *msg_str = "MESSAGE=%s";
127 const auto msg_tuple = std::make_tuple(msg_str, std::forward<Msg>(msg));
128
Adriana Kobylak7d0692a2016-12-06 15:13:23 -0600129 constexpr auto transactionStr = "TRANSACTION_ID=%lld";
130 auto transactionId = sdbusplus::server::transaction::get_id();
131
Adriana Kobylak91da4532016-07-20 12:42:55 -0500132 auto log_tuple = std::tuple_cat(details::prio<L>(),
133 msg_tuple,
Adriana Kobylak7d0692a2016-12-06 15:13:23 -0600134 entry(transactionStr, transactionId),
135 std::forward<Entry>(e)...);
Adriana Kobylak91da4532016-07-20 12:42:55 -0500136 details::log(log_tuple);
137}
138
Joseph Reynolds8f6f7fc2018-05-04 10:11:00 -0500139template<class T>
140struct is_printf_argtype
141 : std::integral_constant<
142 bool,
143 (std::is_integral<typename std::remove_reference<T>::type>::value ||
144 std::is_enum<typename std::remove_reference<T>::type>::value ||
145 std::is_floating_point<typename
146 std::remove_reference<T>::type>::value ||
147 std::is_pointer<typename std::decay<T>::type>::value)>
148{};
149
150template<class T>
151struct is_char_ptr_argtype
152 : std::integral_constant<
153 bool,
154 (std::is_pointer<typename std::decay<T>::type>::value &&
155 std::is_same<typename std::remove_cv<typename
156 std::remove_pointer<typename
157 std::decay<T>::type>::type>::type,
158 char>::value)>
159{};
160
161template<bool...>
162struct bool_pack;
163
164template<bool... bs>
165using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>;
166
Adriana Kobylak91da4532016-07-20 12:42:55 -0500167template <typename Arg, typename ...Args>
168constexpr auto entry(Arg&& arg, Args&&... args)
169{
Joseph Reynolds8f6f7fc2018-05-04 10:11:00 -0500170 static_assert(is_char_ptr_argtype<Arg>::value,
171 "bad argument type: use char*");
172 static_assert(all_true<is_printf_argtype<Args>::value...>::value,
173 "bad argument type: use string.c_str() if needed");
Adriana Kobylak91da4532016-07-20 12:42:55 -0500174 const auto entry_tuple = std::make_tuple(std::forward<Arg>(arg),
Joseph Reynolds8f6f7fc2018-05-04 10:11:00 -0500175 std::forward<Args>(args)...);
Adriana Kobylak91da4532016-07-20 12:42:55 -0500176 return entry_tuple;
177}
178
179} // namespace logging
180
181} // namespace phosphor