1 /**
2  * Copyright © 2020 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 #pragma once
17 
18 #include <systemd/sd-journal.h>
19 
20 #include <phosphor-logging/log.hpp>
21 
22 #include <string>
23 #include <vector>
24 
25 namespace phosphor::power::regulators
26 {
27 
28 /**
29  * @class Journal
30  *
31  * Abstract base class that provides a journal interface.
32  *
33  * The interface is used to write messages/log entries to the system journal.
34  */
35 class Journal
36 {
37   public:
38     // Specify which compiler-generated methods we want
39     Journal() = default;
40     Journal(const Journal&) = delete;
41     Journal(Journal&&) = delete;
42     Journal& operator=(const Journal&) = delete;
43     Journal& operator=(Journal&&) = delete;
44     virtual ~Journal() = default;
45 
46     /**
47      * Gets the journal messages that have the specified field set to the
48      * specified value.
49      *
50      * The messages in the returned vector are ordered from oldest to newest.
51      *
52      * @param field journal field name
53      * @param fieldValue expected field value
54      * @param max Maximum number of messages to return.  Specify 0 to return all
55      *            matching messages.
56      * @return matching messages from the journal
57      */
58     virtual std::vector<std::string> getMessages(const std::string& field,
59                                                  const std::string& fieldValue,
60                                                  unsigned int max = 0) = 0;
61 
62     /**
63      * Logs a debug message in the system journal.
64      *
65      * @param message message to log
66      */
67     virtual void logDebug(const std::string& message) = 0;
68 
69     /**
70      * Logs debug messages in the system journal.
71      *
72      * @param messages messages to log
73      */
74     virtual void logDebug(const std::vector<std::string>& messages) = 0;
75 
76     /**
77      * Logs an error message in the system journal.
78      *
79      * @param message message to log
80      */
81     virtual void logError(const std::string& message) = 0;
82 
83     /**
84      * Logs error messages in the system journal.
85      *
86      * @param messages messages to log
87      */
88     virtual void logError(const std::vector<std::string>& messages) = 0;
89 
90     /**
91      * Logs an informational message in the system journal.
92      *
93      * @param message message to log
94      */
95     virtual void logInfo(const std::string& message) = 0;
96 
97     /**
98      * Logs informational messages in the system journal.
99      *
100      * @param messages messages to log
101      */
102     virtual void logInfo(const std::vector<std::string>& messages) = 0;
103 };
104 
105 /**
106  * @class SystemdJournal
107  *
108  * Implementation of the Journal interface that writes to the systemd journal.
109  */
110 class SystemdJournal : public Journal
111 {
112   public:
113     // Specify which compiler-generated methods we want
114     SystemdJournal() = default;
115     SystemdJournal(const SystemdJournal&) = delete;
116     SystemdJournal(SystemdJournal&&) = delete;
117     SystemdJournal& operator=(const SystemdJournal&) = delete;
118     SystemdJournal& operator=(SystemdJournal&&) = delete;
119     virtual ~SystemdJournal() = default;
120 
121     /** @copydoc Journal::getMessages() */
122     virtual std::vector<std::string> getMessages(const std::string& field,
123                                                  const std::string& fieldValue,
124                                                  unsigned int max) override;
125 
126     /** @copydoc Journal::logDebug(const std::string&) */
logDebug(const std::string & message)127     virtual void logDebug(const std::string& message) override
128     {
129         using namespace phosphor::logging;
130         log<level::DEBUG>(message.c_str());
131     }
132 
133     /** @copydoc Journal::logDebug(const std::vector<std::string>&) */
logDebug(const std::vector<std::string> & messages)134     virtual void logDebug(const std::vector<std::string>& messages) override
135     {
136         for (const std::string& message : messages)
137         {
138             logDebug(message);
139         }
140     }
141 
142     /** @copydoc Journal::logError(const std::string&) */
logError(const std::string & message)143     virtual void logError(const std::string& message) override
144     {
145         using namespace phosphor::logging;
146         log<level::ERR>(message.c_str());
147     }
148 
149     /** @copydoc Journal::logError(const std::vector<std::string>&) */
logError(const std::vector<std::string> & messages)150     virtual void logError(const std::vector<std::string>& messages) override
151     {
152         for (const std::string& message : messages)
153         {
154             logError(message);
155         }
156     }
157 
158     /** @copydoc Journal::logInfo(const std::string&) */
logInfo(const std::string & message)159     virtual void logInfo(const std::string& message) override
160     {
161         using namespace phosphor::logging;
162         log<level::INFO>(message.c_str());
163     }
164 
165     /** @copydoc Journal::logInfo(const std::vector<std::string>&) */
logInfo(const std::vector<std::string> & messages)166     virtual void logInfo(const std::vector<std::string>& messages) override
167     {
168         for (const std::string& message : messages)
169         {
170             logInfo(message);
171         }
172     }
173 
174   private:
175     /**
176      * Gets the value of the specified field for the current journal entry.
177      *
178      * Returns an empty string if the current journal entry does not have the
179      * specified field.
180      *
181      * @param journal current journal entry
182      * @param field journal field name
183      * @return field value
184      */
185     std::string getFieldValue(sd_journal* journal, const std::string& field);
186 
187     /**
188      * Gets the realtime (wallclock) timestamp for the current journal entry.
189      *
190      * @param journal current journal entry
191      * @return timestamp as a date/time string
192      */
193     std::string getTimeStamp(sd_journal* journal);
194 };
195 
196 } // namespace phosphor::power::regulators
197