rippled
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 <ripple/basics/chrono.h>
21 #include <ripple/basics/Log.h>
22 #include <ripple/basics/contract.h>
23 #include <boost/algorithm/string.hpp>
24 #include <cassert>
25 #include <fstream>
26 #include <functional>
27 #include <iostream>
28 #include <memory>
29 #include <mutex>
30 
31 namespace ripple {
32 
33 Logs::Sink::Sink (std::string const& partition,
34  beast::severities::Severity thresh, Logs& logs)
35  : beast::Journal::Sink (thresh, false)
36  , logs_(logs)
37  , partition_(partition)
38 {
39 }
40 
41 void
43 {
44  if (level < threshold())
45  return;
46 
47  logs_.write (level, partition_, text, console());
48 }
49 
50 //------------------------------------------------------------------------------
51 
53  : m_stream (nullptr)
54 {
55 }
56 
57 bool Logs::File::isOpen () const noexcept
58 {
59  return m_stream != nullptr;
60 }
61 
62 bool Logs::File::open (boost::filesystem::path const& path)
63 {
64  close ();
65 
66  bool wasOpened = false;
67 
68  // VFALCO TODO Make this work with Unicode file paths
70  new std::ofstream (path.c_str (), std::fstream::app));
71 
72  if (stream->good ())
73  {
74  m_path = path;
75 
76  m_stream = std::move (stream);
77 
78  wasOpened = true;
79  }
80 
81  return wasOpened;
82 }
83 
85 {
86  close ();
87 
88  return open (m_path);
89 }
90 
92 {
93  m_stream = nullptr;
94 }
95 
96 void Logs::File::write (char const* text)
97 {
98  if (m_stream != nullptr)
99  (*m_stream) << text;
100 }
101 
102 void Logs::File::writeln (char const* text)
103 {
104  if (m_stream != nullptr)
105  {
106  (*m_stream) << text;
107  (*m_stream) << std::endl;
108  }
109 }
110 
111 //------------------------------------------------------------------------------
112 
114  : thresh_ (thresh) // default severity
115 {
116 }
117 
118 bool
119 Logs::open (boost::filesystem::path const& pathToLogFile)
120 {
121  return file_.open(pathToLogFile);
122 }
123 
125 Logs::get (std::string const& name)
126 {
127  std::lock_guard lock (mutex_);
128  auto const result =
129  sinks_.emplace(name, makeSink(name, thresh_));
130  return *result.first->second;
131 }
132 
135 {
136  return get(name);
137 }
138 
141 {
142  return beast::Journal (get(name));
143 }
144 
147 {
148  return thresh_;
149 }
150 
151 void
153 {
154  std::lock_guard lock (mutex_);
155  thresh_ = thresh;
156  for (auto& sink : sinks_)
157  sink.second->threshold (thresh);
158 }
159 
162 {
164  std::lock_guard lock (mutex_);
165  list.reserve (sinks_.size());
166  for (auto const& [name, sink] : sinks_)
167  list.emplace_back(name, toString(fromSeverity(sink->threshold())));
168  return list;
169 }
170 
171 void
173  std::string const& text, bool console)
174 {
175  std::string s;
176  format (s, text, level, partition);
177  std::lock_guard lock (mutex_);
178  file_.writeln (s);
179  if (! silent_)
180  std::cerr << s << '\n';
181  // VFALCO TODO Fix console output
182  //if (console)
183  // out_.write_console(s);
184 }
185 
188 {
189  std::lock_guard lock (mutex_);
190  bool const wasOpened = file_.closeAndReopen ();
191  if (wasOpened)
192  return "The log file was closed and reopened.";
193  return "The log file could not be closed and reopened.";
194 }
195 
198  beast::severities::Severity threshold)
199 {
200  return std::make_unique<Sink>(
201  name, threshold, *this);
202 }
203 
206 {
207  using namespace beast::severities;
208  switch (level)
209  {
210  case kTrace: return lsTRACE;
211  case kDebug: return lsDEBUG;
212  case kInfo: return lsINFO;
213  case kWarning: return lsWARNING;
214  case kError: return lsERROR;
215 
216  default:
217  assert(false);
218  [[fallthrough]];
219  case kFatal:
220  break;
221  }
222 
223  return lsFATAL;
224 }
225 
228 {
229  using namespace beast::severities;
230  switch (level)
231  {
232  case lsTRACE: return kTrace;
233  case lsDEBUG: return kDebug;
234  case lsINFO: return kInfo;
235  case lsWARNING: return kWarning;
236  case lsERROR: return kError;
237  default:
238  assert(false);
239  [[fallthrough]];
240  case lsFATAL:
241  break;
242  }
243 
244  return kFatal;
245 }
246 
249 {
250  switch (s)
251  {
252  case lsTRACE: return "Trace";
253  case lsDEBUG: return "Debug";
254  case lsINFO: return "Info";
255  case lsWARNING: return "Warning";
256  case lsERROR: return "Error";
257  case lsFATAL: return "Fatal";
258  default:
259  assert (false);
260  return "Unknown";
261  }
262 }
263 
266 {
267  if (boost::iequals (s, "trace"))
268  return lsTRACE;
269 
270  if (boost::iequals (s, "debug"))
271  return lsDEBUG;
272 
273  if (boost::iequals (s, "info") || boost::iequals (s, "information"))
274  return lsINFO;
275 
276  if (boost::iequals (s, "warn") || boost::iequals (s, "warning") || boost::iequals (s, "warnings"))
277  return lsWARNING;
278 
279  if (boost::iequals (s, "error") || boost::iequals (s, "errors"))
280  return lsERROR;
281 
282  if (boost::iequals (s, "fatal") || boost::iequals (s, "fatals"))
283  return lsFATAL;
284 
285  return lsINVALID;
286 }
287 
288 void
289 Logs::format (std::string& output, std::string const& message,
290  beast::severities::Severity severity, std::string const& partition)
291 {
292  output.reserve (message.size() + partition.size() + 100);
293 
295 
296  output += " ";
297  if (! partition.empty ())
298  output += partition + ":";
299 
300  using namespace beast::severities;
301  switch (severity)
302  {
303  case kTrace: output += "TRC "; break;
304  case kDebug: output += "DBG "; break;
305  case kInfo: output += "NFO "; break;
306  case kWarning: output += "WRN "; break;
307  case kError: output += "ERR "; break;
308  default:
309  assert(false);
310  [[fallthrough]];
311  case kFatal: output += "FTL "; break;
312  }
313 
314  output += message;
315 
316  // Limit the maximum length of the output
317  if (output.size() > maximumMessageCharacters)
318  {
319  output.resize (maximumMessageCharacters - 3);
320  output += "...";
321  }
322 
323  // Attempt to prevent sensitive information from appearing in log files by
324  // redacting it with asterisks.
325  auto scrubber = [&output](char const* token)
326  {
327  auto first = output.find(token);
328 
329  // If we have found the specified token, then attempt to isolate the
330  // sensitive data (it's enclosed by double quotes) and mask it off:
331  if (first != std::string::npos)
332  {
333  first = output.find ('\"', first + std::strlen(token));
334 
335  if (first != std::string::npos)
336  {
337  auto last = output.find('\"', ++first);
338 
339  if (last == std::string::npos)
340  last = output.size();
341 
342  output.replace (first, last - first, last - first, '*');
343  }
344  }
345  };
346 
347  scrubber ("\"seed\"");
348  scrubber ("\"seed_hex\"");
349  scrubber ("\"secret\"");
350  scrubber ("\"master_key\"");
351  scrubber ("\"master_seed\"");
352  scrubber ("\"master_seed_hex\"");
353  scrubber ("\"passphrase\"");
354 }
355 
356 //------------------------------------------------------------------------------
357 
359 {
360 private:
364 
365 public:
367  : sink_ (beast::Journal::getNullSink())
368  {
369  }
370 
371  DebugSink (DebugSink const&) = delete;
372  DebugSink& operator=(DebugSink const&) = delete;
373 
374  DebugSink(DebugSink&&) = delete;
375  DebugSink& operator=(DebugSink&&) = delete;
376 
379  {
380  std::lock_guard _(m_);
381 
382  using std::swap;
383  swap (holder_, sink);
384 
385  if (holder_)
386  sink_ = *holder_;
387  else
388  sink_ = beast::Journal::getNullSink();
389 
390  return sink;
391  }
392 
394  get()
395  {
396  std::lock_guard _(m_);
397  return sink_.get();
398  }
399 };
400 
401 static
402 DebugSink&
404 {
405  static DebugSink _;
406  return _;
407 }
408 
412 {
413  return debugSink().set(std::move(sink));
414 }
415 
418 {
419  return beast::Journal (debugSink().get());
420 }
421 
422 } // ripple
beast::Journal::Sink
Abstraction for the underlying message destination.
Definition: Journal.h:76
beast::severities::kTrace
@ kTrace
Definition: Journal.h:36
ripple::lsINFO
@ lsINFO
Definition: Log.h:41
ripple::DebugSink::DebugSink
DebugSink()
Definition: Log.cpp:366
std::string::resize
T resize(T... args)
std::strlen
T strlen(T... args)
fstream
ripple::Logs::partition_severities
std::vector< std::pair< std::string, std::string > > partition_severities() const
Definition: Log.cpp:161
std::string
STL class.
ripple::Logs::thresh_
beast::severities::Severity thresh_
Definition: Log.h:152
ripple::Logs::File::close
void close()
Close the system file if it is open.
Definition: Log.cpp:91
ripple::Logs
Manages partitions for logging.
Definition: Log.h:49
functional
ripple::lsTRACE
@ lsTRACE
Definition: Log.h:38
ripple::Logs::File::writeln
void writeln(char const *text)
write to the log file and append an end of line marker.
Definition: Log.cpp:102
ripple::Logs::File::write
void write(char const *text)
write to the log file.
Definition: Log.cpp:96
ripple::debugSink
static DebugSink & debugSink()
Definition: Log.cpp:403
std::vector::reserve
T reserve(T... args)
std::vector
STL class.
std::string::find
T find(T... args)
std::map::size
T size(T... args)
ripple::lsFATAL
@ lsFATAL
Definition: Log.h:45
std::map::emplace
T emplace(T... args)
ripple::Logs::sinks_
std::map< std::string, std::unique_ptr< beast::Journal::Sink >, boost::beast::iless > sinks_
Definition: Log.h:151
std::reference_wrapper::get
T get(T... args)
std::lock_guard
STL class.
beast::severities
A namespace for easy access to logging severity values.
Definition: Journal.h:29
std::cerr
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::Logs::File::File
File()
Construct with no associated system file.
Definition: Log.cpp:52
ripple::Logs::operator[]
beast::Journal::Sink & operator[](std::string const &name)
Definition: Log.cpp:134
iostream
beast::Journal::getNullSink
static Sink & getNullSink()
Returns a Sink which does nothing.
Definition: beast_Journal.cpp:67
ripple::Logs::Sink::write
void write(beast::severities::Severity level, std::string const &text) override
Write text to the sink at the specified severity.
Definition: Log.cpp:42
ripple::Logs::File::closeAndReopen
bool closeAndReopen()
Close and re-open the system file associated with the log This assists in interoperating with externa...
Definition: Log.cpp:84
ripple::debugLog
beast::Journal debugLog()
Returns a debug journal.
Definition: Log.cpp:417
ripple::DebugSink::set
std::unique_ptr< beast::Journal::Sink > set(std::unique_ptr< beast::Journal::Sink > sink)
Definition: Log.cpp:378
ripple::lsINVALID
@ lsINVALID
Definition: Log.h:37
std::string::replace
T replace(T... args)
ripple::DebugSink
Definition: Log.cpp:358
ripple::Logs::toString
static std::string toString(LogSeverity s)
Definition: Log.cpp:248
ripple::Logs::fromSeverity
static LogSeverity fromSeverity(beast::severities::Severity level)
Definition: Log.cpp:205
ripple::Logs::rotate
std::string rotate()
Definition: Log.cpp:187
std::reference_wrapper< beast::Journal::Sink >
ripple::Logs::operator=
Logs & operator=(Logs const &)=delete
std::ofstream
STL class.
ripple::setDebugLogSink
std::unique_ptr< beast::Journal::Sink > setDebugLogSink(std::unique_ptr< beast::Journal::Sink > sink)
Set the sink for the debug journal.
Definition: Log.cpp:410
beast::Journal::Sink::Sink
Sink()=delete
ripple::Logs::Sink
Definition: Log.h:52
ripple::Logs::File::isOpen
bool isOpen() const noexcept
Determine if a system file is associated with the log.
Definition: Log.cpp:57
ripple::Logs::File::open
bool open(boost::filesystem::path const &path)
Associate a system file with the log.
Definition: Log.cpp:62
ripple::Logs::fromString
static LogSeverity fromString(std::string const &s)
Definition: Log.cpp:265
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:60
beast::severities::kInfo
@ kInfo
Definition: Journal.h:38
memory
ripple::Logs::Logs
Logs(beast::severities::Severity level)
Definition: Log.cpp:113
std::swap
T swap(T... args)
ripple::Logs::file_
File file_
Definition: Log.h:153
beast::severities::kError
@ kError
Definition: Journal.h:40
ripple::Logs::threshold
beast::severities::Severity threshold() const
Definition: Log.cpp:146
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
std::endl
T endl(T... args)
ripple::Logs::journal
beast::Journal journal(std::string const &name)
Definition: Log.cpp:140
ripple::Logs::makeSink
virtual std::unique_ptr< beast::Journal::Sink > makeSink(std::string const &partition, beast::severities::Severity startingLevel)
Definition: Log.cpp:197
ripple::Logs::maximumMessageCharacters
@ maximumMessageCharacters
Definition: Log.h:230
ripple::Logs::silent_
bool silent_
Definition: Log.h:154
beast::severities::Severity
Severity
Severity level / threshold of a Journal message.
Definition: Journal.h:32
ripple::DebugSink::get
beast::Journal::Sink & get()
Definition: Log.cpp:394
ripple::lsERROR
@ lsERROR
Definition: Log.h:44
beast::severities::kWarning
@ kWarning
Definition: Journal.h:39
cassert
beast::severities::kDebug
@ kDebug
Definition: Journal.h:37
mutex
ripple::DebugSink::sink_
std::reference_wrapper< beast::Journal::Sink > sink_
Definition: Log.cpp:361
ripple::DebugSink::m_
std::mutex m_
Definition: Log.cpp:363
ripple::Logs::toSeverity
static beast::severities::Severity toSeverity(LogSeverity level)
Definition: Log.cpp:227
ripple::DebugSink::holder_
std::unique_ptr< beast::Journal::Sink > holder_
Definition: Log.cpp:362
beast::severities::kFatal
@ kFatal
Definition: Journal.h:41
ripple::Logs::write
void write(beast::severities::Severity level, std::string const &partition, std::string const &text, bool console)
Definition: Log.cpp:172
std::unique_ptr< std::ofstream >
ripple::LogSeverity
LogSeverity
Definition: Log.h:35
ripple::lsWARNING
@ lsWARNING
Definition: Log.h:42
ripple::Logs::mutex_
std::mutex mutex_
Definition: Log.h:148
ripple::Logs::get
beast::Journal::Sink & get(std::string const &name)
Definition: Log.cpp:125
ripple::Logs::format
static void format(std::string &output, std::string const &message, beast::severities::Severity severity, std::string const &partition)
Definition: Log.cpp:289
ripple::lsDEBUG
@ lsDEBUG
Definition: Log.h:40
ripple::Logs::open
bool open(boost::filesystem::path const &pathToLogFile)
Definition: Log.cpp:119
beast
Definition: base_uint.h:582
std::chrono::system_clock::now
T now(T... args)