rippled
Loading...
Searching...
No Matches
Log.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpl/basics/Log.h>
21#include <xrpl/basics/chrono.h>
22#include <xrpl/beast/utility/Journal.h>
23#include <xrpl/beast/utility/instrumentation.h>
24
25#include <boost/algorithm/string/predicate.hpp>
26#include <boost/filesystem/path.hpp>
27
28#include <chrono>
29#include <cstring>
30#include <fstream>
31#include <functional>
32#include <iostream>
33#include <memory>
34#include <mutex>
35#include <string>
36#include <utility>
37#include <vector>
38
39namespace ripple {
40
42 std::string const& partition,
44 Logs& logs)
45 : beast::Journal::Sink(thresh, false), logs_(logs), partition_(partition)
46{
47}
48
49void
51{
52 if (level < threshold())
53 return;
54
55 logs_.write(level, partition_, text, console());
56}
57
58void
61 std::string const& text)
62{
63 logs_.write(level, partition_, text, console());
64}
65
66//------------------------------------------------------------------------------
67
68Logs::File::File() : m_stream(nullptr)
69{
70}
71
72bool
73Logs::File::isOpen() const noexcept
74{
75 return m_stream != nullptr;
76}
77
78bool
79Logs::File::open(boost::filesystem::path const& path)
80{
81 close();
82
83 bool wasOpened = false;
84
85 // VFALCO TODO Make this work with Unicode file paths
87 new std::ofstream(path.c_str(), std::fstream::app));
88
89 if (stream->good())
90 {
91 m_path = path;
92
93 m_stream = std::move(stream);
94
95 wasOpened = true;
96 }
97
98 return wasOpened;
99}
100
101bool
103{
104 close();
105
106 return open(m_path);
107}
108
109void
111{
112 m_stream = nullptr;
113}
114
115void
116Logs::File::write(char const* text)
117{
118 if (m_stream != nullptr)
119 (*m_stream) << text;
120}
121
122void
123Logs::File::writeln(char const* text)
124{
125 if (m_stream != nullptr)
126 {
127 (*m_stream) << text;
128 (*m_stream) << std::endl;
129 }
130}
131
132//------------------------------------------------------------------------------
133
135 : thresh_(thresh) // default severity
136{
137}
138
139bool
140Logs::open(boost::filesystem::path const& pathToLogFile)
141{
142 return file_.open(pathToLogFile);
143}
144
147{
149 auto const result = sinks_.emplace(name, makeSink(name, thresh_));
150 return *result.first->second;
151}
152
155{
156 return get(name);
157}
158
161{
162 return beast::Journal(get(name));
163}
164
167{
168 return thresh_;
169}
170
171void
173{
175 thresh_ = thresh;
176 for (auto& sink : sinks_)
177 sink.second->threshold(thresh);
178}
179
182{
185 list.reserve(sinks_.size());
186 for (auto const& [name, sink] : sinks_)
187 list.emplace_back(name, toString(fromSeverity(sink->threshold())));
188 return list;
189}
190
191void
194 std::string const& partition,
195 std::string const& text,
196 bool console)
197{
198 std::string s;
199 format(s, text, level, partition);
201 file_.writeln(s);
202 if (!silent_)
203 std::cerr << s << '\n';
204 // VFALCO TODO Fix console output
205 // if (console)
206 // out_.write_console(s);
207}
208
211{
213 bool const wasOpened = file_.closeAndReopen();
214 if (wasOpened)
215 return "The log file was closed and reopened.";
216 return "The log file could not be closed and reopened.";
217}
218
221{
222 return std::make_unique<Sink>(name, threshold, *this);
223}
224
227{
228 using namespace beast::severities;
229 switch (level)
230 {
231 case kTrace:
232 return lsTRACE;
233 case kDebug:
234 return lsDEBUG;
235 case kInfo:
236 return lsINFO;
237 case kWarning:
238 return lsWARNING;
239 case kError:
240 return lsERROR;
241
242 // LCOV_EXCL_START
243 default:
244 UNREACHABLE("ripple::Logs::fromSeverity : invalid severity");
245 [[fallthrough]];
246 // LCOV_EXCL_STOP
247 case kFatal:
248 break;
249 }
250
251 return lsFATAL;
252}
253
256{
257 using namespace beast::severities;
258 switch (level)
259 {
260 case lsTRACE:
261 return kTrace;
262 case lsDEBUG:
263 return kDebug;
264 case lsINFO:
265 return kInfo;
266 case lsWARNING:
267 return kWarning;
268 case lsERROR:
269 return kError;
270 // LCOV_EXCL_START
271 default:
272 UNREACHABLE("ripple::Logs::toSeverity : invalid severity");
273 [[fallthrough]];
274 // LCOV_EXCL_STOP
275 case lsFATAL:
276 break;
277 }
278
279 return kFatal;
280}
281
284{
285 switch (s)
286 {
287 case lsTRACE:
288 return "Trace";
289 case lsDEBUG:
290 return "Debug";
291 case lsINFO:
292 return "Info";
293 case lsWARNING:
294 return "Warning";
295 case lsERROR:
296 return "Error";
297 case lsFATAL:
298 return "Fatal";
299 // LCOV_EXCL_START
300 default:
301 UNREACHABLE("ripple::Logs::toString : invalid severity");
302 return "Unknown";
303 // LCOV_EXCL_STOP
304 }
305}
306
309{
310 if (boost::iequals(s, "trace"))
311 return lsTRACE;
312
313 if (boost::iequals(s, "debug"))
314 return lsDEBUG;
315
316 if (boost::iequals(s, "info") || boost::iequals(s, "information"))
317 return lsINFO;
318
319 if (boost::iequals(s, "warn") || boost::iequals(s, "warning") ||
320 boost::iequals(s, "warnings"))
321 return lsWARNING;
322
323 if (boost::iequals(s, "error") || boost::iequals(s, "errors"))
324 return lsERROR;
325
326 if (boost::iequals(s, "fatal") || boost::iequals(s, "fatals"))
327 return lsFATAL;
328
329 return lsINVALID;
330}
331
332void
334 std::string& output,
335 std::string const& message,
337 std::string const& partition)
338{
339 output.reserve(message.size() + partition.size() + 100);
340
342
343 output += " ";
344 if (!partition.empty())
345 output += partition + ":";
346
347 using namespace beast::severities;
348 switch (severity)
349 {
350 case kTrace:
351 output += "TRC ";
352 break;
353 case kDebug:
354 output += "DBG ";
355 break;
356 case kInfo:
357 output += "NFO ";
358 break;
359 case kWarning:
360 output += "WRN ";
361 break;
362 case kError:
363 output += "ERR ";
364 break;
365 // LCOV_EXCL_START
366 default:
367 UNREACHABLE("ripple::Logs::format : invalid severity");
368 [[fallthrough]];
369 // LCOV_EXCL_STOP
370 case kFatal:
371 output += "FTL ";
372 break;
373 }
374
375 output += message;
376
377 // Limit the maximum length of the output
378 if (output.size() > maximumMessageCharacters)
379 {
381 output += "...";
382 }
383
384 // Attempt to prevent sensitive information from appearing in log files by
385 // redacting it with asterisks.
386 auto scrubber = [&output](char const* token) {
387 auto first = output.find(token);
388
389 // If we have found the specified token, then attempt to isolate the
390 // sensitive data (it's enclosed by double quotes) and mask it off:
391 if (first != std::string::npos)
392 {
393 first = output.find('\"', first + std::strlen(token));
394
395 if (first != std::string::npos)
396 {
397 auto last = output.find('\"', ++first);
398
399 if (last == std::string::npos)
400 last = output.size();
401
402 output.replace(first, last - first, last - first, '*');
403 }
404 }
405 };
406
407 scrubber("\"seed\"");
408 scrubber("\"seed_hex\"");
409 scrubber("\"secret\"");
410 scrubber("\"master_key\"");
411 scrubber("\"master_seed\"");
412 scrubber("\"master_seed_hex\"");
413 scrubber("\"passphrase\"");
414}
415
416//------------------------------------------------------------------------------
417
419{
420private:
424
425public:
426 DebugSink() : sink_(beast::Journal::getNullSink())
427 {
428 }
429
430 DebugSink(DebugSink const&) = delete;
431 DebugSink&
432 operator=(DebugSink const&) = delete;
433
434 DebugSink(DebugSink&&) = delete;
435 DebugSink&
436 operator=(DebugSink&&) = delete;
437
440 {
442
443 using std::swap;
444 swap(holder_, sink);
445
446 if (holder_)
447 sink_ = *holder_;
448 else
450
451 return sink;
452 }
453
456 {
458 return sink_.get();
459 }
460};
461
462static DebugSink&
464{
465 static DebugSink _;
466 return _;
467}
468
471{
472 return debugSink().set(std::move(sink));
473}
474
477{
478 return beast::Journal(debugSink().get());
479}
480
481} // namespace ripple
Abstraction for the underlying message destination.
Definition Journal.h:76
A generic endpoint for log messages.
Definition Journal.h:60
static Sink & getNullSink()
Returns a Sink which does nothing.
beast::Journal::Sink & get()
Definition Log.cpp:455
DebugSink(DebugSink &&)=delete
DebugSink(DebugSink const &)=delete
std::unique_ptr< beast::Journal::Sink > holder_
Definition Log.cpp:422
std::reference_wrapper< beast::Journal::Sink > sink_
Definition Log.cpp:421
DebugSink & operator=(DebugSink &&)=delete
std::mutex m_
Definition Log.cpp:423
DebugSink & operator=(DebugSink const &)=delete
std::unique_ptr< beast::Journal::Sink > set(std::unique_ptr< beast::Journal::Sink > sink)
Definition Log.cpp:439
bool isOpen() const noexcept
Determine if a system file is associated with the log.
Definition Log.cpp:73
bool closeAndReopen()
Close and re-open the system file associated with the log This assists in interoperating with externa...
Definition Log.cpp:102
void close()
Close the system file if it is open.
Definition Log.cpp:110
void write(char const *text)
write to the log file.
Definition Log.cpp:116
void writeln(char const *text)
write to the log file and append an end of line marker.
Definition Log.cpp:123
File()
Construct with no associated system file.
Definition Log.cpp:68
bool open(boost::filesystem::path const &path)
Associate a system file with the log.
Definition Log.cpp:79
void write(beast::severities::Severity level, std::string const &text) override
Write text to the sink at the specified severity.
Definition Log.cpp:50
void writeAlways(beast::severities::Severity level, std::string const &text) override
Bypass filter and write text to the sink at the specified severity.
Definition Log.cpp:59
Manages partitions for logging.
Definition Log.h:52
beast::Journal::Sink & get(std::string const &name)
Definition Log.cpp:146
beast::severities::Severity thresh_
Definition Log.h:167
static LogSeverity fromString(std::string const &s)
Definition Log.cpp:308
void write(beast::severities::Severity level, std::string const &partition, std::string const &text, bool console)
Definition Log.cpp:192
std::map< std::string, std::unique_ptr< beast::Journal::Sink >, boost::beast::iless > sinks_
Definition Log.h:166
File file_
Definition Log.h:168
beast::severities::Severity threshold() const
Definition Log.cpp:166
std::mutex mutex_
Definition Log.h:161
static std::string toString(LogSeverity s)
Definition Log.cpp:283
beast::Journal journal(std::string const &name)
Definition Log.cpp:160
virtual std::unique_ptr< beast::Journal::Sink > makeSink(std::string const &partition, beast::severities::Severity startingLevel)
Definition Log.cpp:220
std::string rotate()
Definition Log.cpp:210
static beast::severities::Severity toSeverity(LogSeverity level)
Definition Log.cpp:255
static void format(std::string &output, std::string const &message, beast::severities::Severity severity, std::string const &partition)
Definition Log.cpp:333
bool open(boost::filesystem::path const &pathToLogFile)
Definition Log.cpp:140
std::vector< std::pair< std::string, std::string > > partition_severities() const
Definition Log.cpp:181
bool silent_
Definition Log.h:169
beast::Journal::Sink & operator[](std::string const &name)
Definition Log.cpp:154
Logs(beast::severities::Severity level)
Definition Log.cpp:134
@ maximumMessageCharacters
Definition Log.h:244
static LogSeverity fromSeverity(beast::severities::Severity level)
Definition Log.cpp:226
T emplace_back(T... args)
T emplace(T... args)
T endl(T... args)
T find(T... args)
T is_same_v
A namespace for easy access to logging severity values.
Definition Journal.h:30
Severity
Severity level / threshold of a Journal message.
Definition Journal.h:32
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
@ open
We haven't closed our ledger yet, but others might have.
beast::Journal debugLog()
Returns a debug journal.
Definition Log.cpp:476
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:630
T get(Section const &section, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
std::unique_ptr< beast::Journal::Sink > setDebugLogSink(std::unique_ptr< beast::Journal::Sink > sink)
Set the sink for the debug journal.
Definition Log.cpp:470
static DebugSink & debugSink()
Definition Log.cpp:463
LogSeverity
Definition Log.h:38
@ lsDEBUG
Definition Log.h:42
@ lsINFO
Definition Log.h:43
@ lsERROR
Definition Log.h:46
@ lsWARNING
Definition Log.h:44
@ lsTRACE
Definition Log.h:40
@ lsINVALID
Definition Log.h:39
@ lsFATAL
Definition Log.h:47
T replace(T... args)
T reserve(T... args)
T resize(T... args)
T size(T... args)
T strlen(T... args)
T swap(T... args)