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 default:
243 UNREACHABLE("ripple::Logs::fromSeverity : invalid severity");
244 [[fallthrough]];
245 case kFatal:
246 break;
247 }
248
249 return lsFATAL;
250}
251
254{
255 using namespace beast::severities;
256 switch (level)
257 {
258 case lsTRACE:
259 return kTrace;
260 case lsDEBUG:
261 return kDebug;
262 case lsINFO:
263 return kInfo;
264 case lsWARNING:
265 return kWarning;
266 case lsERROR:
267 return kError;
268 default:
269 UNREACHABLE("ripple::Logs::toSeverity : invalid severity");
270 [[fallthrough]];
271 case lsFATAL:
272 break;
273 }
274
275 return kFatal;
276}
277
280{
281 switch (s)
282 {
283 case lsTRACE:
284 return "Trace";
285 case lsDEBUG:
286 return "Debug";
287 case lsINFO:
288 return "Info";
289 case lsWARNING:
290 return "Warning";
291 case lsERROR:
292 return "Error";
293 case lsFATAL:
294 return "Fatal";
295 default:
296 UNREACHABLE("ripple::Logs::toString : invalid severity");
297 return "Unknown";
298 }
299}
300
303{
304 if (boost::iequals(s, "trace"))
305 return lsTRACE;
306
307 if (boost::iequals(s, "debug"))
308 return lsDEBUG;
309
310 if (boost::iequals(s, "info") || boost::iequals(s, "information"))
311 return lsINFO;
312
313 if (boost::iequals(s, "warn") || boost::iequals(s, "warning") ||
314 boost::iequals(s, "warnings"))
315 return lsWARNING;
316
317 if (boost::iequals(s, "error") || boost::iequals(s, "errors"))
318 return lsERROR;
319
320 if (boost::iequals(s, "fatal") || boost::iequals(s, "fatals"))
321 return lsFATAL;
322
323 return lsINVALID;
324}
325
326void
328 std::string& output,
329 std::string const& message,
331 std::string const& partition)
332{
333 output.reserve(message.size() + partition.size() + 100);
334
336
337 output += " ";
338 if (!partition.empty())
339 output += partition + ":";
340
341 using namespace beast::severities;
342 switch (severity)
343 {
344 case kTrace:
345 output += "TRC ";
346 break;
347 case kDebug:
348 output += "DBG ";
349 break;
350 case kInfo:
351 output += "NFO ";
352 break;
353 case kWarning:
354 output += "WRN ";
355 break;
356 case kError:
357 output += "ERR ";
358 break;
359 default:
360 UNREACHABLE("ripple::Logs::format : invalid severity");
361 [[fallthrough]];
362 case kFatal:
363 output += "FTL ";
364 break;
365 }
366
367 output += message;
368
369 // Limit the maximum length of the output
370 if (output.size() > maximumMessageCharacters)
371 {
373 output += "...";
374 }
375
376 // Attempt to prevent sensitive information from appearing in log files by
377 // redacting it with asterisks.
378 auto scrubber = [&output](char const* token) {
379 auto first = output.find(token);
380
381 // If we have found the specified token, then attempt to isolate the
382 // sensitive data (it's enclosed by double quotes) and mask it off:
383 if (first != std::string::npos)
384 {
385 first = output.find('\"', first + std::strlen(token));
386
387 if (first != std::string::npos)
388 {
389 auto last = output.find('\"', ++first);
390
391 if (last == std::string::npos)
392 last = output.size();
393
394 output.replace(first, last - first, last - first, '*');
395 }
396 }
397 };
398
399 scrubber("\"seed\"");
400 scrubber("\"seed_hex\"");
401 scrubber("\"secret\"");
402 scrubber("\"master_key\"");
403 scrubber("\"master_seed\"");
404 scrubber("\"master_seed_hex\"");
405 scrubber("\"passphrase\"");
406}
407
408//------------------------------------------------------------------------------
409
411{
412private:
416
417public:
418 DebugSink() : sink_(beast::Journal::getNullSink())
419 {
420 }
421
422 DebugSink(DebugSink const&) = delete;
423 DebugSink&
424 operator=(DebugSink const&) = delete;
425
426 DebugSink(DebugSink&&) = delete;
427 DebugSink&
428 operator=(DebugSink&&) = delete;
429
432 {
434
435 using std::swap;
436 swap(holder_, sink);
437
438 if (holder_)
439 sink_ = *holder_;
440 else
442
443 return sink;
444 }
445
448 {
450 return sink_.get();
451 }
452};
453
454static DebugSink&
456{
457 static DebugSink _;
458 return _;
459}
460
463{
464 return debugSink().set(std::move(sink));
465}
466
469{
470 return beast::Journal(debugSink().get());
471}
472
473} // 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:447
DebugSink(DebugSink &&)=delete
DebugSink(DebugSink const &)=delete
std::unique_ptr< beast::Journal::Sink > holder_
Definition: Log.cpp:414
std::reference_wrapper< beast::Journal::Sink > sink_
Definition: Log.cpp:413
DebugSink & operator=(DebugSink &&)=delete
std::mutex m_
Definition: Log.cpp:415
DebugSink & operator=(DebugSink const &)=delete
std::unique_ptr< beast::Journal::Sink > set(std::unique_ptr< beast::Journal::Sink > sink)
Definition: Log.cpp:431
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:302
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:279
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:253
static void format(std::string &output, std::string const &message, beast::severities::Severity severity, std::string const &partition)
Definition: Log.cpp:327
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)
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:468
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.
Definition: BasicConfig.h:355
std::unique_ptr< beast::Journal::Sink > setDebugLogSink(std::unique_ptr< beast::Journal::Sink > sink)
Set the sink for the debug journal.
Definition: Log.cpp:462
static DebugSink & debugSink()
Definition: Log.cpp:455
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)