/** * Copyright (c) 2021 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #ifndef _OB_TRACE_H #define _OB_TRACE_H #include "ob_trace_def.h" #include "lib/list/ob_dlist.h" #include "lib/utility/utility.h" #include "lib/ob_errno.h" // ? #include "lib/ob_define.h" // ? #define MAX_TRACE_LOG_SIZE (1L << 13) // 8K #define SET_TRACE_BUFFER(buffer, size) OBTRACE->set_trace_buffer(buffer, size) #define FLT_BEGIN_TRACE() (OBTRACE->begin()) #define FLT_END_TRACE() (OBTRACE->end()) #define FLT_BEGIN_SPAN(span_type) FLT_BEGIN_CHILD_SPAN(span_type) #define FLT_BEGIN_CHILD_SPAN(span_type) (OBTRACE->begin_span(::oceanbase::trace::ObSpanType::span_type, GET_SPANLEVEL(::oceanbase::trace::ObSpanType::span_type), false)) #define FLT_BEGIN_FOLLOW_SPAN(span_type) (OBTRACE->begin_span(::oceanbase::trace::ObSpanType::span_type, GET_SPANLEVEL(::oceanbase::trace::ObSpanType::span_type), true)) #define FLT_END_SPAN(span) \ if (OB_NOT_NULL(span)) { \ OBTRACE->end_span(span); \ if (span->span_id_.is_inited() && OBTRACE->is_auto_flush()) { \ FLUSH_TRACE(); \ } \ } #define FLT_RESET_SPAN() (OBTRACE->reset_span()) #define FLT_END_CURRENT_SPAN() FLT_END_SPAN(OBTRACE->last_active_span_) #define FLT_SET_TAG(...) (OBTRACE->set_tag(__VA_ARGS__)) #define FLT_SET_LOG() #define FLT_SET_TRACE_LEVEL(level) (OBTRACE->set_level(level)) #define FLT_SET_AUTO_FLUSH(value) (OBTRACE->set_auto_flush(value)) #define INIT_SPAN(span) \ if (OB_NOT_NULL(span) && 0 == span->span_id_.high_) { \ span->span_id_.low_ = trace::UUID::gen_rand(); \ span->span_id_.high_ = span->start_ts_; \ } namespace oceanbase { namespace sql { class ObFLTSpanMgr; extern ObFLTSpanMgr* get_flt_span_manager(); extern int handle_span_record(char* buf, const int64_t buf_len, ObFLTSpanMgr* flt_span_manager); } } #define FLUSH_TRACE() ::oceanbase::trace::flush_trace(); #define FLTSpanGuard(span_type) ::oceanbase::trace::__ObFLTSpanGuard __##span_type##__LINE__(::oceanbase::trace::ObSpanType::span_type, GET_SPANLEVEL(::oceanbase::trace::ObSpanType::span_type)) #define OBTRACE ::oceanbase::trace::ObTrace::get_instance() namespace oceanbase { namespace trace { extern void flush_trace(); extern double get_random_percentage(); struct UUID { static UUID gen(); static uint64_t gen_rand(); UUID() : low_(0), high_(0) {} explicit UUID(const char* uuid); bool equal(const UUID& that) const { return 0 == memcmp(this, &that, sizeof(UUID)); } void reset() { low_ = 0; high_ = 0; } OB_INLINE bool is_inited() const { return low_ != 0 || high_ != 0; } int tostring(char* buf, const int64_t buf_len, int64_t& pos) const; int serialize(char* buf, const int64_t buf_len, int64_t& pos) const; int deserialize(const char* buf, const int64_t buf_len, int64_t& pos); int64_t get_serialize_size() const { return 16; } int64_t to_string(char* buf, const int64_t buf_len) const { int64_t pos = 0; int ret = tostring(buf, buf_len, pos); if (OB_FAIL(ret)) { pos = 0; } return pos; } union { struct { uint64_t low_; uint64_t high_; }; struct { uint32_t time_low; uint16_t time_mid; uint16_t time_hi_and_version; uint8_t clock_seq_hi_and_reserved; uint8_t clock_seq_low; uint8_t node[6]; }; }; }; struct FltTransCtx { public: FltTransCtx() : trace_id_(), span_id_(), policy_(0) {} TO_STRING_KV(K_(trace_id), K_(span_id), K_(level), K_(auto_flush)); public: UUID trace_id_; UUID span_id_; union { uint8_t policy_; struct { uint8_t level_ : 7; bool auto_flush_ : 1; }; }; }; struct ObTagCtxBase { ObTagCtxBase() {} virtual ~ObTagCtxBase() {} virtual int tostring(char* buf, const int64_t buf_len, int64_t& pos) { int ret = common::OB_SUCCESS; const auto l = strlen(__tag_name_mapper[tag_type_]); if (pos + l + 7 >= buf_len) { buf[std::min(pos - 1, buf_len - 1)] = '\0'; ret = common::OB_BUF_NOT_ENOUGH; } else { buf[pos++] = '{'; buf[pos++] = '\"'; IGNORE_RETURN strcpy(buf + pos, __tag_name_mapper[tag_type_]); pos += l; buf[pos++] = '\"'; buf[pos++] = ':'; buf[pos] = '\0'; } return ret; } ObTagCtxBase* next_; uint16_t tag_type_; }; // if T has member to_string, add quote for it. template int tag_to_string(char* buf, const int64_t buf_len, int64_t& pos, const T& value, common::TrueType) { int ret = common::OB_SUCCESS; if (pos + value.length() + 4 >= buf_len) { ret = common::OB_BUF_NOT_ENOUGH; } else { buf[pos++] = '\"'; ret = common::logdata_print_obj(buf, buf_len, pos, value); buf[pos++] = '\"'; buf[pos++] = '}'; buf[pos] = '\0'; } return ret; } // else use default to_string template int tag_to_string(char* buf, const int64_t buf_len, int64_t& pos, const T& value, common::FalseType) { int ret = common::OB_SUCCESS; if (OB_FAIL(common::logdata_print_obj(buf, buf_len, pos, value))) { // do nothing } else if (pos + 1 >= buf_len) { ret = common::OB_BUF_NOT_ENOUGH; } else { buf[pos++] = '}'; buf[pos] = '\0'; } return ret; } template struct ObTagCtx final : public ObTagCtxBase { ObTagCtx() {} virtual ~ObTagCtx() override {} virtual int tostring(char* buf, const int64_t buf_len, int64_t& pos) override { int ret = common::OB_SUCCESS; if (OB_FAIL(ObTagCtxBase::tostring(buf, buf_len, pos))) { // do nothing } else { ret = tag_to_string(buf, buf_len, pos, data_, common::BoolType()); } return ret; } T data_; }; struct ObSpanCtx final : public common::ObDLinkBase { ObSpanCtx(); UUID span_id_; ObSpanCtx* source_span_; int64_t start_ts_; int64_t end_ts_; ObTagCtxBase* tags_; uint16_t span_type_; bool is_follow_; }; struct ObTrace { static constexpr uint64_t MAGIC_CODE = 0x1234567887654321ul; static constexpr int64_t DEFAULT_BUFFER_SIZE = (1L << 16); // do not used now static constexpr int64_t MIN_BUFFER_SIZE = (1L << 13); static ObTrace* get_instance(); static void set_trace_buffer(void* buffer, int64_t buffer_size); ObTrace(int64_t buffer_size); void init(FltTransCtx &flt_ctx) { root_span_id_ = flt_ctx.span_id_; trace_id_ = flt_ctx.trace_id_; policy_ = flt_ctx.policy_; } void init(UUID trace_id, UUID root_span_id, uint8_t policy = 0); bool is_inited() { return check_magic() && trace_id_.is_inited(); } UUID begin(); void end(); ObSpanCtx* begin_span(uint32_t span_type, uint8_t level, bool is_follow); void end_span(ObSpanCtx* span_id); void reset_span(); template void set_tag(ObTagType tag_type, const T& value, Targs... Fargs) { if (trace_id_.is_inited() && OB_NOT_NULL(last_active_span_) && GET_TAGLEVEL(tag_type) <= level_) { if (OB_UNLIKELY(!append_tag(tag_type, value))) { FLUSH_TRACE(); IGNORE_RETURN append_tag(tag_type, value); } set_tag(std::forward(Fargs)...); } } int serialize(char* buf, const int64_t buf_len, int64_t& pos) const; int deserialize(const char* buf, const int64_t buf_len, int64_t& pos); int64_t get_serialize_size() const { return 33; } OB_INLINE UUID get_trace_id() { return trace_id_; } OB_INLINE UUID get_root_span_id() { return root_span_id_; } OB_INLINE uint8_t get_policy() { return policy_; } OB_INLINE void set_level(uint8_t level) { level_ = 0x7f & level; } OB_INLINE void set_auto_flush(bool auto_flush) { auto_flush_ = auto_flush; } OB_INLINE bool is_auto_flush() { return auto_flush_; } void check_leak_span(); void reset(); void dump_span(); template::value && !std::is_convertible::value, bool>::type = true> bool append_tag(ObTagType tag_type, const T& value) { int ret = false; if (offset_ + sizeof(ObTagCtx) >= buffer_size_) { // do nothing } else { ObTagCtx* tag = new (data_ + offset_) ObTagCtx; tag->next_ = last_active_span_->tags_; last_active_span_->tags_ = tag; tag->tag_type_ = tag_type; tag->data_ = value; offset_ += sizeof(ObTagCtx); ret = true; } return ret; } template::value, bool>::type = true> bool append_tag(ObTagType tag_type, const T& value) { int ret = false; common::ObString v(""); if (OB_ISNULL(value.ptr())) { // do nothing } else { v = value; } auto l = value.length(); if (offset_ + sizeof(ObTagCtx) + l + 1 - sizeof(void*) >= buffer_size_) { // do nothing } else { ObTagCtx* tag = new (data_ + offset_) ObTagCtx; tag->next_ = last_active_span_->tags_; last_active_span_->tags_ = tag; tag->tag_type_ = tag_type; memcpy(&(tag->data_), value.ptr(), l); offset_ += (sizeof(ObTagCtx) + l + 1 - sizeof(void*)); data_[offset_ - 1] = '\0'; ret = true; } return ret; } template::value, bool>::type = true> bool append_tag(ObTagType tag_type, const T& value) { return append_tag(tag_type, OB_ISNULL(value) ? common::ObString("") : common::ObString(value)); } private: bool check_magic() { return MAGIC_CODE == magic_code_; } void set_tag() {} private: static thread_local ObTrace* save_buffer; uint64_t magic_code_; public: int64_t buffer_size_; int64_t offset_; common::ObDList current_span_; common::ObDList freed_span_; ObSpanCtx* last_active_span_; private: UUID trace_id_; UUID root_span_id_; union { uint8_t policy_; struct { uint8_t level_ : 7; bool auto_flush_ : 1; }; }; uint64_t seq_; char data_[0]; }; class __ObFLTSpanGuard { public: __ObFLTSpanGuard(uint32_t span_type, uint8_t level) { span_ = OBTRACE->begin_span(span_type, level, false); #ifndef NDEBUG if (OB_NOT_NULL(span_) && span_->span_id_.is_inited()) { FLT_SET_TAG(span_back_trace, common::lbt()); } #endif } ~__ObFLTSpanGuard() { FLT_END_SPAN(span_); } private: ObSpanCtx* span_; }; template<> int ObTagCtx::tostring(char* buf, const int64_t buf_len, int64_t& pos); } // trace } // oceanbase #endif /* _OB_TRACE_H */