• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender / 947394036

pending completion
947394036

push

gitlab-ci

kacf
chore: Treat events with no state transitions as fatal.

This was discussed with the team members. Since an unhandled event is
almost guaranteed to hang the state machine, then it's better to
terminate and let systemd try to restart us, in the hopes that
recovery will still work.

Signed-off-by: Kristian Amlie <kristian.amlie@northern.tech>

3 of 3 new or added lines in 1 file covered. (100.0%)

4268 of 5997 relevant lines covered (71.17%)

148.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.69
/common/log/platform/boost/boost_log.cpp
1
// Copyright 2023 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
#include <common/log.hpp>
16

17

18
#include <boost/smart_ptr/shared_ptr.hpp>
19
#include <boost/core/null_deleter.hpp>
20
#include <boost/date_time/posix_time/posix_time.hpp>
21
#include <boost/log/common.hpp>
22
#include <boost/log/expressions.hpp>
23
#include <boost/log/attributes.hpp>
24
#include <boost/log/sinks.hpp>
25
#include <boost/log/sources/logger.hpp>
26
#include <boost/log/utility/manipulators/add_value.hpp>
27
#include <boost/log/attributes/scoped_attribute.hpp>
28
#include <boost/log/support/date_time.hpp>
29

30
#include <string>
31
#include <fstream>
32
#include <common/error.hpp>
33
#include <common/expected.hpp>
34

35
namespace mender {
36
namespace common {
37
namespace log {
38

39
namespace logging = boost::log;
40
namespace expr = boost::log::expressions;
41
namespace sinks = boost::log::sinks;
42
namespace attrs = boost::log::attributes;
43
namespace src = boost::log::sources;
44

45
namespace error = mender::common::error;
46
namespace expected = mender::common::expected;
47

48
using namespace std;
49

50

51
const LogErrorCategoryClass LogErrorCategory;
52

53
const char *LogErrorCategoryClass::name() const noexcept {
×
54
        return "LogErrorCategory";
×
55
}
56

57
string LogErrorCategoryClass::message(int code) const {
×
58
        switch (code) {
×
59
        case NoError:
×
60
                return "Success";
×
61
        case InvalidLogLevelError:
×
62
                return "Invalid log level given";
×
63
        case LogFileError:
×
64
                return "Bad log file";
×
65
        default:
×
66
                return "Unknown";
×
67
        }
68
}
69

70
error::Error MakeError(LogErrorCode code, const string &msg) {
2✔
71
        return error::Error(error_condition(code, LogErrorCategory), msg);
4✔
72
}
73

74
ExpectedLogLevel StringToLogLevel(const string &level_str) {
78✔
75
        if (level_str == "fatal") {
78✔
76
                return ExpectedLogLevel(LogLevel::Fatal);
×
77
        } else if (level_str == "error") {
78✔
78
                return ExpectedLogLevel(LogLevel::Error);
×
79
        } else if (level_str == "warning") {
78✔
80
                return ExpectedLogLevel(LogLevel::Warning);
×
81
        } else if (level_str == "info") {
78✔
82
                return ExpectedLogLevel(LogLevel::Info);
156✔
83
        } else if (level_str == "debug") {
×
84
                return ExpectedLogLevel(LogLevel::Debug);
×
85
        } else if (level_str == "trace") {
×
86
                return ExpectedLogLevel(LogLevel::Trace);
×
87
        } else {
88
                return ExpectedLogLevel(expected::unexpected(MakeError(
×
89
                        LogErrorCode::InvalidLogLevelError, "'" + level_str + "' is not a valid log level")));
×
90
        }
91
}
92

93
static void LogfmtFormatter(logging::record_view const &rec, logging::formatting_ostream &strm) {
5,538✔
94
        strm << "record_id=" << logging::extract<unsigned int>("RecordID", rec) << " ";
5,538✔
95

96
        auto level = logging::extract<LogLevel>("Severity", rec);
5,538✔
97
        if (level) {
5,538✔
98
                std::string lvl = ToStringLogLevel(level.get());
11,076✔
99
                strm << "severity=" << lvl << " ";
5,538✔
100
        }
101

102
        auto val = logging::extract<boost::posix_time::ptime>("TimeStamp", rec);
5,538✔
103
        if (val) {
5,538✔
104
                strm << "time=\"" << val.get() << "\" ";
5,538✔
105
        }
106

107
        auto name = logging::extract<std::string>("Name", rec);
5,538✔
108
        if (name) {
5,538✔
109
                strm << "name=\"" << name.get() << "\" ";
5,538✔
110
        }
111

112
        for (auto f : rec.attribute_values()) {
36,804✔
113
                auto field = logging::extract<LogField>(f.first.string(), rec);
31,266✔
114
                if (field) {
31,266✔
115
                        strm << field.get().key << "=\"" << field.get().value << "\" ";
3,576✔
116
                }
117
        }
118

119
        strm << "msg=\"" << rec[expr::smessage] << "\" ";
5,538✔
120
}
5,538✔
121

122
static void SetupLoggerSinks() {
316✔
123
        typedef sinks::synchronous_sink<sinks::text_ostream_backend> text_sink;
124
        boost::shared_ptr<text_sink> sink(new text_sink);
316✔
125

126
        {
127
                text_sink::locked_backend_ptr pBackend = sink->locked_backend();
632✔
128
                boost::shared_ptr<std::ostream> pStream(&std::clog, boost::null_deleter());
632✔
129
                pBackend->add_stream(pStream);
316✔
130
        }
131

132
        sink->set_formatter(&LogfmtFormatter);
316✔
133

134
        logging::core::get()->add_sink(sink);
316✔
135
}
316✔
136

137
static void SetupLoggerAttributes() {
316✔
138
        attrs::counter<unsigned int> RecordID(1);
632✔
139
        logging::core::get()->add_global_attribute("RecordID", RecordID);
316✔
140

141
        attrs::local_clock TimeStamp;
316✔
142
        logging::core::get()->add_global_attribute("TimeStamp", TimeStamp);
316✔
143
}
316✔
144

145
Logger::Logger(const string &name) :
595✔
146
        Logger(name, global_logger_.Level()) {
595✔
147
}
595✔
148

149
Logger::Logger(const string &name, LogLevel level) :
912✔
150
        name_(name),
151
        level_(level) {
912✔
152
        src::severity_logger<LogLevel> slg;
1,824✔
153
        slg.add_attribute("Name", attrs::constant<std::string>(name));
912✔
154
        this->logger = slg;
912✔
155
}
912✔
156

157
void Logger::Log_(LogLevel level, const string &message) {
5,538✔
158
        BOOST_LOG_SEV(this->logger, level) << message;
11,076✔
159
}
5,538✔
160

161
void Logger::SetLevel(LogLevel level) {
525✔
162
        this->level_ = level;
525✔
163
}
525✔
164

165
LogLevel Logger::Level() {
918✔
166
        return this->level_;
918✔
167
}
168

169
void Logger::AddField(const LogField &field) {
140✔
170
        this->logger.add_attribute(field.key, attrs::constant<LogField>(field));
140✔
171
        return;
140✔
172
}
173

174
Logger Setup() {
316✔
175
        SetupLoggerSinks();
316✔
176
        SetupLoggerAttributes();
316✔
177
#ifdef NDEBUG
178
        return Logger("Global", LogLevel::Info);
179
#else
180
        return Logger("Global", LogLevel::Debug);
632✔
181
#endif
182
}
183

184
Logger global_logger_ = Setup();
185

186
void SetLevel(LogLevel level) {
386✔
187
        global_logger_.SetLevel(level);
386✔
188
}
386✔
189

190
error::Error SetupFileLogging(const string &log_file_path, bool exclusive) {
2✔
191
        typedef sinks::synchronous_sink<sinks::text_ostream_backend> text_sink;
192
        boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>();
4✔
193

194
        // Add a stream to write log to
195
        auto log_stream = boost::make_shared<std::ofstream>();
4✔
196
        errno = 0;
2✔
197
        log_stream->open(log_file_path);
2✔
198
        if (!(*log_stream.get())) {
2✔
199
                auto io_errno = errno;
1✔
200
                return MakeError(
201
                        LogErrorCode::LogFileError,
202
                        "Failed to open '" + log_file_path + "' for logging: " + strerror(io_errno));
2✔
203
        }
204
        sink->set_formatter(&LogfmtFormatter);
1✔
205

206
        sink->locked_backend()->add_stream(log_stream);
1✔
207
        sink->locked_backend()->auto_flush(true);
1✔
208

209
        if (exclusive) {
1✔
210
                logging::core::get()->remove_all_sinks();
1✔
211
        }
212

213
        // Register the sink in the logging core
214
        logging::core::get()->add_sink(sink);
1✔
215

216
        return error::NoError;
1✔
217
}
218

219
LogLevel Level() {
7✔
220
        return global_logger_.Level();
7✔
221
}
222

223
void Log_(LogLevel level, const string message) {
×
224
        global_logger_.Log(level, message);
×
225
}
×
226

227
void Fatal(const string &message) {
×
228
        global_logger_.Log(LogLevel::Fatal, message);
×
229
        std::abort();
×
230
}
231
void Error(const string &message) {
26✔
232
        return global_logger_.Log(LogLevel::Error, message);
26✔
233
}
234
void Warning(const string &message) {
7✔
235
        return global_logger_.Log(LogLevel::Warning, message);
7✔
236
}
237
void Info(const string &message) {
32✔
238
        return global_logger_.Log(LogLevel::Info, message);
32✔
239
}
240
void Debug(const string &message) {
332✔
241
        return global_logger_.Log(LogLevel::Debug, message);
332✔
242
}
243
void Trace(const string &message) {
2,860✔
244
        return global_logger_.Log(LogLevel::Trace, message);
2,860✔
245
}
246

247

248
} // namespace log
249
} // namespace common
250
} // namespace mender
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc