#pragma once #include #include #include #include #include #include #include #include #include #include #include namespace xrpl { /** * Manages partitions for logging. */ class Logs { private: class Sink : public beast::Journal::Sink { private: Logs& logs_; std::string partition_; public: Sink(std::string partition, beast::Severity thresh, Logs& logs); Sink(Sink const&) = delete; Sink& operator=(Sink const&) = delete; void write(beast::Severity level, std::string const& text) override; void writeAlways(beast::Severity level, std::string const& text) override; }; /** * Manages a system file containing logged output. * The system file remains open during program execution. Interfaces * are provided for interoperating with standard log management * tools like logrotate(8): * http://linuxcommand.org/man_pages/logrotate8.html * @note None of the listed interfaces are thread-safe. */ class File { public: /** * Construct with no associated system file. * A system file may be associated later with @ref open. * @see open */ File(); /** * Destroy the object. * If a system file is associated, it will be flushed and closed. */ ~File() = default; /** * Determine if a system file is associated with the log. * @return `true` if a system file is associated and opened for * writing. */ [[nodiscard]] bool isOpen() const noexcept; /** * Associate a system file with the log. * If the file does not exist an attempt is made to create it * and open it for writing. If the file already exists an attempt is * made to open it for appending. * If a system file is already associated with the log, it is closed * first. * @return `true` if the file was opened. */ bool open(boost::filesystem::path const& path); /** * Close and re-open the system file associated with the log * This assists in interoperating with external log management tools. * @return `true` if the file was opened. */ bool closeAndReopen(); /** * Close the system file if it is open. */ void close(); /** * write to the log file. * Does nothing if there is no associated system file. */ void write(char const* text); /** * write to the log file and append an end of line marker. * Does nothing if there is no associated system file. */ void writeln(char const* text); /** * Write to the log file using std::string. */ /** @{ */ void write(std::string const& str) { write(str.c_str()); } void writeln(std::string const& str) { writeln(str.c_str()); } /** @} */ private: std::unique_ptr stream_; boost::filesystem::path path_; }; std::mutex mutable mutex_; std::map, boost::beast::iless> sinks_; beast::Severity thresh_; File file_; bool silent_ = false; public: Logs(beast::Severity level); Logs(Logs const&) = delete; Logs& operator=(Logs const&) = delete; virtual ~Logs() = default; bool open(boost::filesystem::path const& pathToLogFile); beast::Journal::Sink& get(std::string const& name); beast::Journal::Sink& operator[](std::string const& name); beast::Journal journal(std::string const& name); beast::Severity threshold() const; void threshold(beast::Severity thresh); std::vector> partitionSeverities() const; void write( beast::Severity level, std::string const& partition, std::string const& text, bool console); std::string rotate(); /** * Set flag to write logs to stderr (false) or not (true). * * @param bSilent Set flag accordingly. */ void silent(bool bSilent) { silent_ = bSilent; } virtual std::unique_ptr makeSink(std::string const& partition, beast::Severity startingLevel); public: static std::string toString(beast::Severity s); static std::optional fromString(std::string const& s); private: // Maximum line length for log messages. // If the message exceeds this length it will be truncated with ellipses. static constexpr auto kMaximumMessageCharacters = 12 * 1024; static void format( std::string& output, std::string const& message, beast::Severity severity, std::string const& partition); }; // Wraps a Journal::Stream to skip evaluation of // expensive argument lists if the stream is not active. #ifndef JLOG #define JLOG(x) \ if (!(x)) \ ; \ else \ x #endif #ifndef CLOG #define CLOG(ss) \ if (!(ss)) \ ; \ else \ *ss #endif //------------------------------------------------------------------------------ // Debug logging: /** * Set the sink for the debug journal. * * @param sink unique_ptr to new debug Sink. * @return unique_ptr to the previous Sink. nullptr if there was no Sink. */ std::unique_ptr setDebugLogSink(std::unique_ptr sink); /** * Returns a debug journal. * The journal may drain to a null sink, so its output * may never be seen. Never use it for critical * information. */ beast::Journal debugLog(); } // namespace xrpl