// file : bbot/diagnostics.hxx -*- C++ -*- // license : MIT; see accompanying LICENSE file #ifndef BBOT_DIAGNOSTICS_HXX #define BBOT_DIAGNOSTICS_HXX #include #include // Note: not . namespace bbot { using butl::diag_record; // Throw this exception to terminate the process. The handler should // assume that the diagnostics has already been issued. // class failed: public std::exception {}; // Verbosity level. Update documentation for --verbose if changing. // // 0 - disabled // 1 - high-level information messages // 2 - essential underlying commands that are being executed // 3 - all underlying commands that are being executed // 4 - information that could be helpful to the user // 5 - information that could be helpful to the developer // 6 - even more detailed information // // While uint8 is more than enough, use uint16 for the ease of printing. // extern uint16_t verb; template inline void l1 (const F& f) {if (verb >= 1) f ();} template inline void l2 (const F& f) {if (verb >= 2) f ();} template inline void l3 (const F& f) {if (verb >= 3) f ();} template inline void l4 (const F& f) {if (verb >= 4) f ();} template inline void l5 (const F& f) {if (verb >= 5) f ();} template inline void l6 (const F& f) {if (verb >= 6) f ();} // Diagnostic facility, base infrastructure. // using butl::diag_stream; using butl::diag_epilogue; // Diagnostic facility, project specifics. // struct simple_prologue_base { explicit simple_prologue_base (const char* type, const char* name, const char* data) : type_ (type), name_ (name), data_ (data) {} void operator() (const diag_record& r) const; private: const char* type_; const char* name_; const char* data_; }; struct basic_mark_base { using simple_prologue = butl::diag_prologue; // If data if not NULL, then we print it as (data) after name. For // example: // // trace: main(foo): bar // explicit basic_mark_base (const char* type, const char* indent = "\n ", const char* name = nullptr, const char* data = nullptr, diag_epilogue* epilogue = nullptr) : type_ (type), name_ (name), data_ (data), indent_ (indent), epilogue_ (epilogue) {} simple_prologue operator() () const { return simple_prologue (indent_, epilogue_, type_, name_, data_); } public: const char* type_; const char* name_; const char* data_; const char* indent_; diag_epilogue* const epilogue_; }; using basic_mark = butl::diag_mark; extern basic_mark error; extern basic_mark warn; extern basic_mark info; extern basic_mark text; // trace // extern const char* trace_type; extern const char* trace_indent; struct trace_mark_base: basic_mark_base { explicit trace_mark_base (const char* name, const char* data = nullptr); }; using trace_mark = butl::diag_mark; class tracer: public trace_mark { public: using trace_mark::trace_mark; // process_run_callback() command tracer interface. // void operator() (const char* const [], std::size_t) const; }; // fail // struct fail_mark_base: basic_mark_base { explicit fail_mark_base (const char* type, const char* indent = "\n ", const char* data = nullptr) : basic_mark_base (type, indent, nullptr, data, [](const diag_record& r, butl::diag_writer* w) { r.flush (w); throw failed (); }) {} // If hard is false, then we fail as an error (but still throw). // simple_prologue operator() (bool hard = true) const { if (hard) return simple_prologue (indent_, epilogue_, type_, name_, data_); simple_prologue r (error ()); r.epilogue = epilogue_; return r; } }; using fail_mark = butl::diag_mark; struct fail_end_base { [[noreturn]] void operator() (const diag_record& r) const { // If we just throw then the record's destructor will see an active // exception and will not flush the record. // r.flush (); throw failed (); } }; using fail_end = butl::diag_noreturn_end; extern fail_mark fail; extern const fail_end endf; // Map to systemd severity prefixes (see sd-daemon(3) for details). Note // that here we assume we will never have location (like file name which // would end up being before the prefix). // // If with_critical is true, then distinguish between fail (critical error, // daemon terminates) and error (non-fatal error, daemon continues to run). // Note that this means we should be careful not to use fail to report // normal errors and vice-versa (see fail hard). // void systemd_diagnostics (bool with_critical); } #endif // BBOT_DIAGNOSTICS_HXX