1 // Copyright (c) 2010, Amar Takhar <verm@aegisub.org> 2 // 3 // Permission to use, copy, modify, and distribute this software for any 4 // purpose with or without fee is hereby granted, provided that the above 5 // copyright notice and this permission notice appear in all copies. 6 // 7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 15 #include <libaegisub/fs_fwd.h> 16 17 #include <boost/interprocess/streams/bufferstream.hpp> 18 #include <cstdint> 19 #include <memory> 20 #include <vector> 21 22 // These macros below aren't a perm solution, it will depend on how annoying they are through 23 // actual usage, and also depends on msvc support. 24 #define LOG_SINK(section, severity) agi::log::Message(section, severity, __FILE__, __FUNCTION__, __LINE__).stream() 25 #define LOG_E(section) LOG_SINK(section, agi::log::Exception) 26 #define LOG_A(section) LOG_SINK(section, agi::log::Assert) 27 #define LOG_W(section) LOG_SINK(section, agi::log::Warning) 28 #define LOG_I(section) LOG_SINK(section, agi::log::Info) 29 #define LOG_D(section) LOG_SINK(section, agi::log::Debug) 30 31 #define LOG_W_IF(cond, section) if (cond) LOG_SINK(section, agi::log::Warning) 32 #define LOG_I_IF(cond, section) if (cond) LOG_SINK(section, agi::log::Info) 33 #define LOG_D_IF(cond, section) if (cond) LOG_SINK(section, agi::log::Debug) 34 35 namespace agi { 36 namespace dispatch { class Queue; } 37 namespace log { 38 39 class LogSink; 40 41 /// Severity levels 42 enum Severity { 43 Exception, ///< Used when exceptions are thrown 44 Assert, ///< Fatal and non-fatal assert logging 45 Warning, ///< Warnings 46 Info, ///< Information only 47 Debug ///< Enabled by default when compiled in debug mode. 48 }; 49 50 /// Short Severity ID 51 /// Set in common/log.cpp, keep this ordered the same as Severity. 52 extern const char *Severity_ID; 53 54 /// Global log sink. 55 extern LogSink *log; 56 57 /// Container to hold a single message 58 struct SinkMessage { 59 std::string message; ///< Formatted message 60 int64_t time; ///< Time at execution in nanoseconds since epoch 61 const char *section; ///< Section info eg "video/open" "video/seek" etc 62 const char *file; ///< Source file 63 const char *func; ///< Function name 64 Severity severity; ///< Severity 65 int line; ///< Source line 66 }; 67 68 class Emitter; 69 70 /// Log sink, single destination for all messages 71 class LogSink { 72 std::vector<SinkMessage> messages; 73 size_t next_idx = 0; 74 std::unique_ptr<dispatch::Queue> queue; 75 76 /// List of pointers to emitters 77 std::vector<std::unique_ptr<Emitter>> emitters; 78 79 public: 80 LogSink(); 81 ~LogSink(); 82 83 /// Insert a message into the sink. 84 void Log(SinkMessage const& sm); 85 86 /// @brief Subscribe an emitter 87 /// @param em Emitter to add 88 void Subscribe(std::unique_ptr<Emitter> em); 89 90 /// @brief Unsubscribe and delete an emitter 91 /// @param em Emitter to delete 92 void Unsubscribe(Emitter *em); 93 94 /// @brief @get the complete (current) log. 95 /// @return Const pointer to internal sink. 96 std::vector<SinkMessage> GetMessages() const; 97 }; 98 99 /// An emitter to produce human readable output for a log sink. 100 class Emitter { 101 public: 102 /// Destructor ~Emitter()103 virtual ~Emitter() { } 104 105 /// Accept a single log entry 106 virtual void log(SinkMessage const& sm)=0; 107 }; 108 109 /// A simple emitter which writes the log to a file in json format 110 class JsonEmitter final : public Emitter { 111 std::unique_ptr<std::ostream> fp; 112 113 public: 114 /// Constructor 115 /// @param directory Directory to write the log file in 116 JsonEmitter(fs::path const& directory); 117 118 void log(SinkMessage const&) override; 119 }; 120 121 /// Generates a message and submits it to the log sink. 122 class Message { 123 boost::interprocess::obufferstream msg; 124 SinkMessage sm; 125 char buffer[2048]; 126 127 public: 128 Message(const char *section, Severity severity, const char *file, const char *func, int line); 129 ~Message(); stream()130 std::ostream& stream() { return msg; } 131 }; 132 133 /// Emit log entries to stdout. 134 class EmitSTDOUT: public Emitter { 135 public: 136 void log(SinkMessage const& sm) override; 137 }; 138 139 } // namespace log 140 } // namespace agi 141