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

mendersoftware / mender / 1019363462

28 Sep 2023 08:41AM UTC coverage: 78.477% (+0.9%) from 77.556%
1019363462

push

gitlab-ci

kacf
chore: Make out `optional` use compatible with C++17.

If the standard is pre-C++17, we use the `optional-lite` library, else
we use the one in `std`.

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

17 of 17 new or added lines in 6 files covered. (100.0%)

5546 of 7067 relevant lines covered (78.48%)

11103.37 hits per line

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

82.86
/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) {
1✔
71
        return error::Error(error_condition(code, LogErrorCategory), msg);
2✔
72
}
73

74
ExpectedLogLevel StringToLogLevel(const string &level_str) {
101✔
75
        if (level_str == "fatal") {
101✔
76
                return ExpectedLogLevel(LogLevel::Fatal);
77
        } else if (level_str == "error") {
101✔
78
                return ExpectedLogLevel(LogLevel::Error);
79
        } else if (level_str == "warning") {
101✔
80
                return ExpectedLogLevel(LogLevel::Warning);
81
        } else if (level_str == "info") {
101✔
82
                return ExpectedLogLevel(LogLevel::Info);
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) {
69,598✔
94
        strm << "record_id=" << logging::extract<unsigned int>("RecordID", rec) << " ";
69,598✔
95

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

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

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

112
        for (auto f : rec.attribute_values()) {
424,610✔
113
                auto field = logging::extract<LogField>(f.first.string(), rec);
×
114
                if (field) {
355,012✔
115
                        strm << field.get().key << "=\"" << field.get().value << "\" ";
7,022✔
116
                }
117
        }
118

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

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

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

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

134
        logging::core::get()->add_sink(sink);
1,988✔
135
}
497✔
136

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

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

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

149
Logger::Logger(const string &name, LogLevel level) :
2,335✔
150
        logger_ {new src::severity_logger<LogLevel>},
×
151
        name_ {name},
152
        level_ {level} {
7,005✔
153
        this->logger_->add_attribute("Name", attrs::constant<std::string>(name));
4,670✔
154
}
2,335✔
155

156
void Logger::Log_(LogLevel level, const string &message) {
69,598✔
157
        BOOST_LOG_SEV(*this->logger_, level) << message;
139,191✔
158
}
69,598✔
159

160
void Logger::SetLevel(LogLevel level) {
462✔
161
        this->level_ = level;
1,047✔
162
}
462✔
163

164
LogLevel Logger::Level() {
569✔
165
        return this->level_;
1,837✔
166
}
167

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

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

183
Logger global_logger_ = Setup();
184

185
void SetLevel(LogLevel level) {
585✔
186
        global_logger_.SetLevel(level);
187
}
585✔
188

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

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

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

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

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

215
        return error::NoError;
216
}
217

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

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

226
void Fatal(const string &message) {
×
227
        global_logger_.Log(LogLevel::Fatal, message);
228
        std::abort();
×
229
}
230
void Error(const string &message) {
232✔
231
        return global_logger_.Log(LogLevel::Error, message);
232✔
232
}
233
void Warning(const string &message) {
357✔
234
        return global_logger_.Log(LogLevel::Warning, message);
357✔
235
}
236
void Info(const string &message) {
1,981✔
237
        return global_logger_.Log(LogLevel::Info, message);
1,981✔
238
}
239
void Debug(const string &message) {
3,764✔
240
        return global_logger_.Log(LogLevel::Debug, message);
3,764✔
241
}
242
void Trace(const string &message) {
62,444✔
243
        return global_logger_.Log(LogLevel::Trace, message);
62,444✔
244
}
245

246

247
} // namespace log
248
} // namespace common
249
} // 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