// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. #pragma once #include #include #include #include #include #include #include #include #include "common/compiler_util.h" #include "common/config.h" #include "fmt/format.h" // more usage can see 'util/debug_points_test.cpp' #define DBUG_EXECUTE_IF(debug_point_name, code) \ if (UNLIKELY(config::enable_debug_points)) { \ auto dp = DebugPoints::instance()->get_debug_point(debug_point_name); \ if (dp) { \ [[maybe_unused]] auto DP_NAME = debug_point_name; \ code; \ } \ } // define some common debug actions // usage example: DBUG_EXECUTE_IF("xxx", DBUG_BLOCK); #define DBUG_BLOCK \ { \ LOG(INFO) << "start debug block " << DP_NAME; \ while (DebugPoints::instance()->is_enable(DP_NAME)) { \ std::this_thread::sleep_for(std::chrono::milliseconds(10)); \ } \ LOG(INFO) << "end debug block " << DP_NAME; \ } namespace doris { struct DebugPoint { std::atomic execute_num {0}; int64_t execute_limit = -1; int64_t expire_ms = -1; std::map params; template T param(const std::string& key, T default_value = T()) { auto it = params.find(key); if (it == params.end()) { return default_value; } if constexpr (std::is_same_v) { if (it->second == "true") { return true; } if (it->second == "false") { return false; } return boost::lexical_cast(it->second); } else if constexpr (std::is_arithmetic_v) { return boost::lexical_cast(it->second); } else if constexpr (std::is_same_v) { return it->second.c_str(); } else { static_assert(std::is_same_v); return it->second; } } }; class DebugPoints { public: bool is_enable(const std::string& name); std::shared_ptr get_debug_point(const std::string& name); void remove(const std::string& name); void clear(); // if not enable debug point or its params not contains `key`, then return `default_value` // url: /api/debug_point/add/name?k1=v1&k2=v2&... template T get_debug_param_or_default(const std::string& name, const std::string& key, const T& default_value) { auto debug_point = get_debug_point(name); return debug_point ? debug_point->param(key, default_value) : default_value; } // url: /api/debug_point/add/name?value=v template T get_debug_param_or_default(const std::string& name, const T& default_value) { return get_debug_param_or_default(name, "value", default_value); } void add(const std::string& name, std::shared_ptr debug_point); // more 'add' functions for convenient use void add(const std::string& name) { add(name, std::make_shared()); } void add_with_params(const std::string& name, const std::map& params) { add(name, std::shared_ptr(new DebugPoint {.params = params})); } template void add_with_value(const std::string& name, const T& value) { add_with_params(name, {{"value", fmt::format("{}", value)}}); } static DebugPoints* instance(); private: DebugPoints(); using DebugPointMap = std::map>; // handler(new_debug_points) void update(std::function&& handler); private: /// TODO: replace atomic_load/store() on shared_ptr (which is deprecated as of C++20) by C++20 std::atomic. /// Clang 15 currently does not support it. std::shared_ptr _debug_points; }; } // namespace doris