blob: be9427514aa39121e3e8afccbb9972240468ff3e [file] [log] [blame]
Bob Kingca08a792020-09-30 14:30:13 +08001
2/**
3 * Copyright © 2020 IBM Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include "journal.hpp"
19
20#include <string.h>
21#include <time.h>
22
23#include <cstdint>
24#include <ctime>
25#include <stdexcept>
26
27using namespace phosphor::logging;
28
29namespace phosphor::power::regulators
30{
31
32class JournalCloser
33{
34 public:
35 JournalCloser() = delete;
36 JournalCloser(const JournalCloser&) = delete;
37 JournalCloser(JournalCloser&&) = delete;
38 JournalCloser& operator=(const JournalCloser&) = delete;
39 JournalCloser& operator=(JournalCloser&&) = delete;
40
41 JournalCloser(sd_journal* journal) : journal{journal}
42 {
43 }
44 ~JournalCloser()
45 {
46 sd_journal_close(journal);
47 }
48
49 private:
50 sd_journal* journal{nullptr};
51};
52
53std::string SystemdJournal::getFieldValue(sd_journal* journal,
54 const char* field) const
55{
56 const char* data{nullptr};
57 size_t length{0};
58
59 // Get field data
60 int rc = sd_journal_get_data(journal, field, (const void**)&data, &length);
61 if (rc < 0)
62 {
63 throw std::runtime_error{
64 std::string{"Failed to read journal entry field: "} +
65 strerror(-rc)};
66 }
67
68 // Get field value
69 size_t prefix{0};
70 const void* eq = memchr(data, '=', length);
71 if (eq)
72 {
73 prefix = (const char*)eq - data + 1;
74 }
75 else
76 {
77 prefix = 0;
78 }
79
80 std::string value{data + prefix, length - prefix};
81
82 return value;
83}
84
85std::vector<std::string>
86 SystemdJournal::getMessages(const std::string& field,
87 const std::string& fieldValue, unsigned int max)
88{
89 sd_journal* journal;
90 std::vector<std::string> messages;
91
92 int rc = sd_journal_open(&journal, SD_JOURNAL_LOCAL_ONLY);
93 if (rc < 0)
94 {
95 throw std::runtime_error{std::string{"Failed to open journal: "} +
96 strerror(-rc)};
97 }
98
99 JournalCloser closer{journal};
100
101 SD_JOURNAL_FOREACH_BACKWARDS(journal)
102 {
103 // Get input field
104 std::string value = getFieldValue(journal, field.c_str());
105
106 // Compare field value and read data
107 if (value == fieldValue)
108 {
109 // Get SYSLOG_IDENTIFIER field
110 std::string syslog = getFieldValue(journal, "SYSLOG_IDENTIFIER");
111
112 // Get _PID field
113 std::string pid = getFieldValue(journal, "_PID");
114
115 // Get MESSAGE field
116 std::string message = getFieldValue(journal, "MESSAGE");
117
118 // Get realtime
119 uint64_t usec{0};
120 rc = sd_journal_get_realtime_usec(journal, &usec);
121 if (rc < 0)
122 {
123 throw std::runtime_error{
124 std::string{"Failed to get journal entry timestamp: "} +
125 strerror(-rc)};
126 }
127
128 // Convert realtime microseconds to date format
129 char dateBuffer[80];
130 std::string date;
131 std::time_t timeInSecs = usec / 1000000;
132 strftime(dateBuffer, sizeof(dateBuffer), "%b %d %H:%M:%S",
133 std::localtime(&timeInSecs));
134 date = dateBuffer;
135
136 // Store value to messages
137 value = date + " " + syslog + "[" + pid + "]: " + message;
138 messages.insert(messages.begin(), value);
139 }
140 // Set the maximum number of messages
141 if ((max != 0) && (messages.size() >= max))
142 {
143 break;
144 }
145 }
146
147 return messages;
148}
149
150} // namespace phosphor::power::regulators