├── .bazelrc ├── .clang-format ├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── main.yml ├── .gitignore ├── BUILD ├── CMakeLists.txt ├── LICENSE ├── README.md ├── WORKSPACE ├── bazel ├── BUILD ├── copts.bzl ├── fmtlib.BUILD ├── osx.tbb.BUILD ├── spdlog.BUILD ├── tbb.BUILD └── third_party_repositories.bzl ├── cmake ├── common.cmake └── third_party.cmake ├── examples ├── CMakeLists.txt ├── abseil │ ├── BUILD │ └── abseil_string.cc ├── benchmark │ ├── BUILD │ └── benchamrk_test.cc ├── cache │ ├── BUILD │ └── cache_test.cc ├── fmt │ ├── BUILD │ └── fmt_test.cc ├── gtest │ ├── BUILD │ └── hello_test.cc ├── json │ ├── BUILD │ └── nlohmann_json_example.cc ├── libevent │ ├── BUILD │ └── libevent_echosrv1.c ├── log │ ├── BUILD │ └── log_test.cc ├── sentinel-cpp │ ├── BUILD │ ├── basic_concurrency_limit.cc │ ├── basic_param_limit.cc │ ├── basic_qps_limit.cc │ └── basic_system_limit.cc └── tbb │ ├── BUILD │ └── tbb_test.cc ├── format.sh ├── sentinel-core ├── BUILD ├── circuitbreaker │ ├── BUILD │ ├── circuit_breaker.cc │ ├── circuit_breaker.h │ ├── error_circuit_breaker.cc │ ├── error_circuit_breaker.h │ ├── rt_circuit_breaker.cc │ ├── rt_circuit_breaker.h │ ├── rule.cc │ ├── rule.h │ ├── rule_manager.cc │ ├── rule_manager.h │ ├── slot.cc │ ├── slot.h │ └── slot_test.cc ├── common │ ├── BUILD │ ├── constants.h │ ├── entry.h │ ├── entry_context.cc │ ├── entry_context.h │ ├── entry_node.h │ ├── entry_result.cc │ ├── entry_result.h │ ├── entry_type.h │ ├── global_status.cc │ ├── global_status.h │ ├── resource_wrapper.h │ ├── rule.h │ ├── string_resource_wrapper.h │ ├── tracer.cc │ ├── tracer.h │ └── tracer_test.cc ├── config │ ├── BUILD │ ├── config_constants.h │ ├── local_config.cc │ ├── local_config.h │ └── local_config_test.cc ├── flow │ ├── BUILD │ ├── default_traffic_shaping_calculator.cc │ ├── default_traffic_shaping_calculator.h │ ├── default_traffic_shaping_checker.cc │ ├── default_traffic_shaping_checker.h │ ├── flow_rule.cc │ ├── flow_rule.h │ ├── flow_rule_checker.cc │ ├── flow_rule_checker.h │ ├── flow_rule_constants.h │ ├── flow_rule_manager.cc │ ├── flow_rule_manager.h │ ├── flow_slot.cc │ ├── flow_slot.h │ ├── flow_slot_test.cc │ ├── throttling_traffic_shaping_checker.cc │ ├── throttling_traffic_shaping_checker.h │ ├── traffic_shaping_calculator.h │ ├── traffic_shaping_checker.h │ ├── traffic_shaping_controller.cc │ ├── traffic_shaping_controller.h │ └── traffic_shaping_controller_test.cc ├── init │ ├── BUILD │ ├── init_target.h │ ├── init_target_registry.h │ └── init_target_registry_test.cc ├── log │ ├── BUILD │ ├── block │ │ ├── BUILD │ │ ├── block_log_task.cc │ │ ├── block_log_task.h │ │ └── block_log_task_test.cc │ ├── log_base.cc │ ├── log_base.h │ ├── log_base_test.cc │ ├── logger.cc │ ├── logger.h │ ├── logger_test.cc │ └── metric │ │ ├── BUILD │ │ ├── metric_log_task.cc │ │ ├── metric_log_task.h │ │ ├── metric_reader.cc │ │ ├── metric_reader.h │ │ ├── metric_reader_test.cc │ │ ├── metric_searcher.cc │ │ ├── metric_searcher.h │ │ ├── metric_searcher_test.cc │ │ ├── metric_test_utils.h │ │ ├── metric_writer.cc │ │ ├── metric_writer.h │ │ └── metric_writer_test.cc ├── param │ ├── BUILD │ ├── param_flow_item.cc │ ├── param_flow_item.h │ ├── param_flow_rule.cc │ ├── param_flow_rule.h │ ├── param_flow_rule_checker.cc │ ├── param_flow_rule_checker.h │ ├── param_flow_rule_constants.h │ ├── param_flow_rule_manager.cc │ ├── param_flow_rule_manager.h │ ├── param_flow_slot.cc │ ├── param_flow_slot.h │ ├── param_flow_slot_test.cc │ └── statistic │ │ ├── BUILD │ │ ├── any_cmp.cc │ │ ├── any_cmp.h │ │ ├── any_cmp_test.cc │ │ ├── lru_cache.h │ │ ├── param_bucket.cc │ │ ├── param_bucket.h │ │ ├── param_event.h │ │ ├── param_leap_array.cc │ │ ├── param_leap_array.h │ │ ├── param_leap_array_key.h │ │ ├── param_metric.cc │ │ ├── param_metric.h │ │ ├── param_metric_test.cc │ │ └── scalable_cache.h ├── property │ ├── BUILD │ ├── dynamic_sentinel_property.h │ ├── dynamic_sentinel_property_test.cc │ ├── property_listener.h │ └── sentinel_property.h ├── public │ ├── BUILD │ ├── sph_u.h │ └── sph_u_test.cc ├── slot │ ├── BUILD │ ├── base │ │ ├── BUILD │ │ ├── default_slot_chain_impl.cc │ │ ├── default_slot_chain_impl.h │ │ ├── default_slot_chain_impl_test.cc │ │ ├── rule_checker_slot.h │ │ ├── slot.h │ │ ├── slot_base.h │ │ ├── slot_chain.h │ │ ├── stats_slot.h │ │ ├── token_result.cc │ │ └── token_result.h │ ├── global_slot_chain.cc │ ├── global_slot_chain.h │ ├── log_slot.cc │ ├── log_slot.h │ ├── resource_node_builder_slot.cc │ ├── resource_node_builder_slot.h │ ├── resource_node_builder_slot_test.cc │ ├── statistic_slot.cc │ ├── statistic_slot.h │ └── statistic_slot_test.cc ├── statistic │ ├── base │ │ ├── BUILD │ │ ├── bucket_leap_array.cc │ │ ├── bucket_leap_array.h │ │ ├── bucket_leap_array_test.cc │ │ ├── leap_array.h │ │ ├── metric.h │ │ ├── metric_bucket.cc │ │ ├── metric_bucket.h │ │ ├── metric_event.h │ │ ├── metric_item.cc │ │ ├── metric_item.h │ │ ├── metric_item_test.cc │ │ ├── sliding_window_metric.cc │ │ ├── sliding_window_metric.h │ │ ├── sliding_window_metric_test.cc │ │ ├── stat_config.h │ │ ├── stat_config_manager.cc │ │ ├── stat_config_manager.h │ │ └── window_wrap.h │ └── node │ │ ├── BUILD │ │ ├── cluster_node.cc │ │ ├── cluster_node.h │ │ ├── node.h │ │ ├── resource_node_storage.cc │ │ ├── resource_node_storage.h │ │ ├── statistic_node.cc │ │ └── statistic_node.h ├── system │ ├── BUILD │ ├── system_rule.cc │ ├── system_rule.h │ ├── system_rule_manager.cc │ ├── system_rule_manager.h │ ├── system_slot.cc │ ├── system_slot.h │ ├── system_slot_mock.h │ ├── system_slot_test.cc │ ├── system_status_listener.cc │ ├── system_status_listener.h │ └── system_status_listener_test.cc ├── test │ └── mock │ │ ├── common │ │ ├── BUILD │ │ ├── mock.cc │ │ └── mock.h │ │ ├── flow │ │ ├── BUILD │ │ ├── mock.cc │ │ └── mock.h │ │ ├── init │ │ ├── BUILD │ │ └── mock.h │ │ ├── property │ │ ├── BUILD │ │ ├── mock.cc │ │ └── mock.h │ │ ├── slot │ │ ├── BUILD │ │ ├── mock.cc │ │ └── mock.h │ │ └── statistic │ │ ├── base │ │ ├── BUILD │ │ ├── mock.cc │ │ └── mock.h │ │ └── node │ │ ├── BUILD │ │ ├── mock.cc │ │ └── mock.h ├── transport │ ├── BUILD │ ├── command │ │ ├── BUILD │ │ ├── command_handler.h │ │ ├── command_request.cc │ │ ├── command_request.h │ │ ├── command_request_test.cc │ │ ├── command_response.h │ │ ├── handler │ │ │ ├── BUILD │ │ │ ├── fetch_cluster_node_handler.cc │ │ │ ├── fetch_cluster_node_handler.h │ │ │ ├── fetch_cluster_node_handler_test.cc │ │ │ ├── fetch_metric_log_handler.cc │ │ │ ├── fetch_metric_log_handler.h │ │ │ ├── get_switch_status_handler.cc │ │ │ ├── get_switch_status_handler.h │ │ │ ├── set_switch_status_handler.cc │ │ │ ├── set_switch_status_handler.h │ │ │ ├── set_switch_status_handler_test.cc │ │ │ ├── version_handler.cc │ │ │ ├── version_handler.h │ │ │ └── vo │ │ │ │ ├── BUILD │ │ │ │ ├── statistic_node_vo.cc │ │ │ │ └── statistic_node_vo.h │ │ ├── http_command_center.cc │ │ ├── http_command_center.h │ │ ├── http_command_utils.cc │ │ ├── http_command_utils.h │ │ ├── http_server.cc │ │ ├── http_server.h │ │ ├── http_server_init_target.cc │ │ └── http_server_init_target.h │ ├── common │ │ ├── BUILD │ │ ├── event_loop_thread.cc │ │ ├── event_loop_thread.h │ │ └── event_loop_thread_test.cc │ └── constants.h └── utils │ ├── BUILD │ ├── file_utils.cc │ ├── file_utils.h │ ├── macros.h │ ├── time_utils.cc │ ├── time_utils.h │ ├── utils.cc │ └── utils.h ├── sentinel-datasource-extension ├── datasource │ ├── BUILD │ ├── abstract_readable_data_source.h │ ├── abstract_readable_data_source_unittests.cc │ ├── converter.h │ └── readable_data_source.h └── test │ └── mock │ └── datasource │ ├── BUILD │ ├── mock.cc │ └── mock.h ├── tests ├── BUILD └── tsan-flow.cc └── third_party └── nlohmann ├── BUILD └── json.hpp /.bazelrc: -------------------------------------------------------------------------------- 1 | # Clang TSAN 2 | build:clang-tsan --copt -fsanitize=thread 3 | build:clang-tsan --linkopt -fsanitize=thread 4 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # Use the Google style in this project. 2 | BasedOnStyle: Google -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | ## Issue Description 9 | 10 | Type: *bug report* or *feature request* 11 | 12 | ### Describe what happened (or what feature you want) 13 | 14 | 15 | ### Describe what you expected to happen 16 | 17 | 18 | ### How to reproduce it (as minimally and precisely as possible) 19 | 20 | 1. 21 | 2. 22 | 3. 23 | 24 | ### Tell us your environment 25 | 26 | 27 | ### Anything else we need to know? 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | ### Describe what this PR does / why we need it 7 | 8 | 9 | ### Does this pull request fix one issue? 10 | 11 | 12 | 13 | ### Describe how you did it 14 | 15 | 16 | ### Describe how to verify it 17 | 18 | 19 | ### Special notes for reviews 20 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: master 6 | pull_request: 7 | branches: "*" 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | java: [8] 16 | os: [ubuntu-18.04] 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - name: Install bazel 22 | run: | 23 | wget https://github.com/bazelbuild/bazel/releases/download/3.7.0/bazel_3.7.0-linux-x86_64.deb 24 | sudo dpkg -i bazel_3.7.0-linux-x86_64.deb 25 | - name: Install clang8 26 | run: | 27 | echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" | sudo tee -a /etc/apt/sources.list 28 | echo "deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" | sudo tee -a /etc/apt/sources.list 29 | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - 30 | sudo apt-get update 31 | sudo apt-get -y install clang-8 clang-format-8 32 | 33 | - name: Clang format checker 34 | run: | 35 | bash format.sh 36 | 37 | - name: Library build 38 | run: | 39 | bazel build //sentinel-core/... && bazel build //sentinel-datasource-extension/... 40 | 41 | - name: Sentinel core unit tests 42 | run: | 43 | bazel test --test_filter=*-ParamMetricTest.TestOperateMetric --test_output=errors --strategy=TestRunner=standalone //sentinel-core/... 44 | 45 | - name: Sentinel datasource extension tests 46 | run: | 47 | bazel build //sentinel-core/... && bazel build //sentinel-datasource-extension/... 48 | 49 | - name: tsan for flow control 50 | run: | 51 | bazel build -c dbg --config=clang-tsan //tests/... && ./bazel-bin/tests/tsan-flow 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bazel-* 2 | BROWSE 3 | /build 4 | /build_* 5 | .cache 6 | /ci/bazel-* 7 | /ci/prebuilt/thirdparty 8 | /ci/prebuilt/thirdparty_build 9 | compile_commands.json 10 | cscope.* 11 | .deps 12 | /docs/landing_source/.bundle 13 | /generated 14 | *.pyc 15 | **/pyformat 16 | SOURCE_VERSION 17 | *.sw* 18 | tags 19 | TAGS 20 | /test/coverage/BUILD 21 | /tools/.aspell.en.pws 22 | .vimrc 23 | .vs 24 | .vscode 25 | .DS_Store 26 | .gdb_history -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_foreign_cc//tools/build_defs:configure.bzl", "configure_make") 2 | # load("@rules_foreign_cc//tools/build_defs:make.bzl", "make") 3 | 4 | configure_make( 5 | name = "libevent", 6 | visibility = ["//visibility:public"], 7 | configure_options = [ 8 | "--enable-shared=no", 9 | "--disable-libevent-regress", 10 | "--disable-openssl", 11 | ], 12 | lib_source = "@com_github_libevent//:all", 13 | out_lib_dir = "lib", 14 | ) 15 | 16 | # make( 17 | # name = "com_github_libtbb", 18 | # visibility = ["//visibility:public"], 19 | # out_lib_dir = "lib", 20 | # lib_source = "@com_github_libtbb//:all", 21 | # ) 22 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | project(sentinel-cpp VERSION 1.0.1 LANGUAGES C CXX) 4 | 5 | set(CMAKE_CXX_STANDARD 14) 6 | 7 | set(SENTINEL_ROOT_DIR "${CMAKE_SOURCE_DIR}") 8 | set(SENTINEL_CORE_ROOT_DIR "${CMAKE_SOURCE_DIR}/sentinel-core") 9 | 10 | include( cmake/common.cmake ) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Sentinel Logo 2 | 3 | [![Build Status](https://travis-ci.org/alibaba/sentinel-cpp.svg?branch=master)](https://travis-ci.org/alibaba/sentinel-cpp) 4 | [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) 5 | [![Gitter](https://badges.gitter.im/alibaba/Sentinel.svg)](https://gitter.im/alibaba/Sentinel) 6 | 7 | # Sentinel: The Sentinel of Your Microservices 8 | 9 | ## Build 10 | 11 | 1. Install the latest version of [Bazel](https://bazel.build/versions/master/docs/install.html) in your environment. 12 | 2. Build the project. 13 | 14 | ```sh 15 | bazel build -c opt //... 16 | ``` 17 | 18 | 3. Run the [QPS limiting demo](https://github.com/alibaba/sentinel-cpp/blob/master/examples/sentinel-cpp/basic_qps_limit.cc): 19 | 20 | ```sh 21 | CSP_SENTINEL_APP_NAME=my-demo ./bazel-bin/examples/sentinel-cpp/sentinel_basic_qps_limit 22 | ``` 23 | -------------------------------------------------------------------------------- /bazel/BUILD: -------------------------------------------------------------------------------- 1 | licenses(["notice"]) # Apache 2.0 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | config_setting( 6 | name = "llvm_compiler", 7 | values = { 8 | "compiler": "llvm", 9 | }, 10 | ) 11 | 12 | config_setting( 13 | name = "windows", 14 | values = { 15 | "cpu": "x64_windows", 16 | }, 17 | ) 18 | 19 | config_setting( 20 | name = "is_osx", 21 | define_values = {"os":"osx"}, 22 | ) 23 | -------------------------------------------------------------------------------- /bazel/copts.bzl: -------------------------------------------------------------------------------- 1 | """ 2 | Flags specified here must not impact ABI. Code compiled with and without these 3 | opts will be linked together, and in some cases headers compiled with and 4 | without these options will be part of the same program. 5 | 6 | We use the same flags as absl. 7 | """ 8 | 9 | load( 10 | "@com_google_absl//absl:copts/GENERATED_copts.bzl", 11 | "ABSL_GCC_EXCEPTIONS_FLAGS", 12 | "ABSL_GCC_FLAGS", 13 | "ABSL_GCC_TEST_FLAGS", 14 | "ABSL_LLVM_EXCEPTIONS_FLAGS", 15 | "ABSL_LLVM_FLAGS", 16 | "ABSL_LLVM_TEST_FLAGS", 17 | "ABSL_MSVC_EXCEPTIONS_FLAGS", 18 | "ABSL_MSVC_FLAGS", 19 | "ABSL_MSVC_LINKOPTS", 20 | "ABSL_MSVC_TEST_FLAGS", 21 | ) 22 | 23 | WERROR = ["-Werror=return-type", "-Werror=switch"] 24 | 25 | DEFAULT_COPTS = select({ 26 | "//bazel:windows": ABSL_MSVC_FLAGS, 27 | "//bazel:llvm_compiler": ABSL_LLVM_FLAGS, 28 | "//conditions:default": ABSL_GCC_FLAGS + WERROR + ["-std=c++14"], 29 | }) 30 | 31 | TEST_COPTS = DEFAULT_COPTS + select({ 32 | "//bazel:windows": ABSL_MSVC_TEST_FLAGS, 33 | "//bazel:llvm_compiler": ABSL_LLVM_TEST_FLAGS, 34 | "//conditions:default": ABSL_GCC_TEST_FLAGS + WERROR + ["-std=c++14"], 35 | }) -------------------------------------------------------------------------------- /bazel/fmtlib.BUILD: -------------------------------------------------------------------------------- 1 | licenses(["notice"]) # Apache 2 2 | 3 | cc_library( 4 | name = "fmtlib", 5 | srcs = glob([ 6 | "fmt/*.cc", 7 | ]), 8 | hdrs = glob([ 9 | "include/fmt/*.h", 10 | ]), 11 | defines = ["FMT_HEADER_ONLY"], 12 | includes = ["include"], 13 | visibility = ["//visibility:public"], 14 | ) 15 | 16 | -------------------------------------------------------------------------------- /bazel/osx.tbb.BUILD: -------------------------------------------------------------------------------- 1 | licenses(["notice"]) # Apache 2 2 | package(default_visibility = ["//visibility:public"]) 3 | 4 | genrule( 5 | name = "build_tbb_osx", 6 | srcs = glob(["**"]) + [ 7 | "@local_config_cc//:toolchain", 8 | ], 9 | cmd = """ 10 | set -e 11 | set -u 12 | WORK_DIR=$$PWD 13 | DEST_DIR=$$PWD/$(@D) 14 | cd $$(dirname $(location :Makefile)) 15 | make 16 | 17 | files=build/*/*.dylib; 18 | echo cp $$files $$DEST_DIR 19 | cp $$files $$DEST_DIR 20 | cd $$WORK_DIR 21 | """, 22 | outs = [ 23 | "libtbb.dylib", 24 | "libtbbmalloc.dylib", 25 | "libtbbmalloc_proxy.dylib", 26 | ], 27 | ) 28 | 29 | cc_library( 30 | name = "tbb_osx", 31 | hdrs = glob([ 32 | "include/serial/**", 33 | "include/tbb/**/**", 34 | ]), 35 | srcs = [ 36 | "libtbb.dylib", 37 | "libtbbmalloc.dylib", 38 | "libtbbmalloc_proxy.dylib", 39 | ], 40 | includes = ["include"], 41 | visibility = ["//visibility:public"], 42 | ) 43 | -------------------------------------------------------------------------------- /bazel/spdlog.BUILD: -------------------------------------------------------------------------------- 1 | licenses(["notice"]) # Apache 2 2 | 3 | cc_library( 4 | name = "spdlog", 5 | hdrs = glob([ 6 | "include/**/*.cc", 7 | "include/**/*.h", 8 | ]), 9 | defines = ["SPDLOG_FMT_EXTERNAL"], 10 | includes = ["include"], 11 | visibility = ["//visibility:public"], 12 | deps = ["@com_github_fmtlib_fmt//:fmtlib"], 13 | ) 14 | 15 | -------------------------------------------------------------------------------- /bazel/tbb.BUILD: -------------------------------------------------------------------------------- 1 | licenses(["notice"]) # Apache 2 2 | package(default_visibility = ["//visibility:public"]) 3 | 4 | genrule( 5 | name = "build_tbb", 6 | srcs = glob(["**"]) + [ 7 | "@local_config_cc//:toolchain", 8 | ], 9 | cmd = """ 10 | set -e 11 | set -u 12 | WORK_DIR=$$PWD 13 | DEST_DIR=$$PWD/$(@D) 14 | cd $$(dirname $(location :Makefile)) 15 | make 16 | 17 | if [[ $$(echo `uname` | grep 'Dar') != "" ]]; then 18 | files=build/*/*.dylib; 19 | else files=build/*/*.so*; 20 | fi 21 | echo cp $$files $$DEST_DIR 22 | cp $$files $$DEST_DIR 23 | cd $$WORK_DIR 24 | """, 25 | outs = [ 26 | "libtbb.so", 27 | "libtbbmalloc.so", 28 | "libtbbmalloc_proxy.so", 29 | "libtbb.so.2", 30 | "libtbbmalloc.so.2", 31 | "libtbbmalloc_proxy.so.2", 32 | ], 33 | ) 34 | 35 | cc_library( 36 | name = "tbb", 37 | hdrs = glob([ 38 | "include/serial/**", 39 | "include/tbb/**/**", 40 | ]), 41 | srcs = [ 42 | "libtbb.so", 43 | "libtbbmalloc.so", 44 | "libtbbmalloc_proxy.so", 45 | "libtbb.so.2", 46 | "libtbbmalloc.so.2", 47 | "libtbbmalloc_proxy.so.2", 48 | ], 49 | includes = ["include"], 50 | visibility = ["//visibility:public"], 51 | ) 52 | -------------------------------------------------------------------------------- /bazel/third_party_repositories.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file") 2 | 3 | all_content = """filegroup(name = "all", srcs = glob(["**"]), visibility = ["//visibility:public"])""" 4 | 5 | def include_third_party_repositories(): 6 | http_archive( 7 | name = "com_github_libevent", 8 | build_file_content = all_content, 9 | strip_prefix = "libevent-2.1.8-stable", 10 | urls = ["https://github.com/libevent/libevent/releases/download/release-2.1.8-stable/libevent-2.1.8-stable.tar.gz"], 11 | ) 12 | 13 | http_archive( 14 | name = "com_github_libtbb", 15 | build_file = "//bazel:tbb.BUILD", 16 | strip_prefix = "oneTBB-2020.3", 17 | urls = ["https://github.com/oneapi-src/oneTBB/archive/v2020.3.tar.gz"], 18 | sha256 = "ebc4f6aa47972daed1f7bf71d100ae5bf6931c2e3144cf299c8cc7d041dca2f3", 19 | ) 20 | 21 | http_archive( 22 | name = "com_github_libtbb_osx", 23 | build_file = "//bazel:osx.tbb.BUILD", 24 | strip_prefix = "oneTBB-2020.3", 25 | urls = ["https://github.com/oneapi-src/oneTBB/archive/v2020.3.tar.gz"], 26 | sha256 = "ebc4f6aa47972daed1f7bf71d100ae5bf6931c2e3144cf299c8cc7d041dca2f3", 27 | ) 28 | 29 | http_archive( 30 | name = "com_github_fmtlib_fmt", 31 | sha256 = "4c0741e10183f75d7d6f730b8708a99b329b2f942dad5a9da3385ab92bb4a15c", 32 | strip_prefix = "fmt-5.3.0", 33 | urls = ["https://github.com/fmtlib/fmt/releases/download/5.3.0/fmt-5.3.0.zip"], 34 | build_file = "//bazel:fmtlib.BUILD", 35 | ) 36 | 37 | http_archive( 38 | name = "com_github_gabime_spdlog", 39 | build_file = "//bazel:spdlog.BUILD", 40 | sha256 = "160845266e94db1d4922ef755637f6901266731c4cb3b30b45bf41efa0e6ab70", 41 | strip_prefix = "spdlog-1.3.1", 42 | urls = ["https://github.com/gabime/spdlog/archive/v1.3.1.tar.gz"], 43 | ) 44 | -------------------------------------------------------------------------------- /cmake/third_party.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required( VERSION 3.14 ) 2 | include( FetchContent ) 3 | 4 | ####################################################################### 5 | # Declare project dependencies 6 | ####################################################################### 7 | 8 | FetchContent_Declare( abseil 9 | GIT_REPOSITORY https://github.com/abseil/abseil-cpp.git 10 | GIT_TAG 20230125.0 11 | ) 12 | 13 | FetchContent_Declare( spdlog 14 | GIT_REPOSITORY https://github.com/gabime/spdlog.git 15 | GIT_TAG v1.11.0 16 | ) 17 | 18 | FetchContent_Declare( onetbb 19 | GIT_REPOSITORY https://github.com/oneapi-src/oneTBB.git 20 | GIT_TAG v2021.9.0 21 | ) 22 | 23 | FetchContent_MakeAvailable(abseil) 24 | 25 | FetchContent_MakeAvailable(spdlog) 26 | 27 | FetchContent_MakeAvailable(onetbb) -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | project(sentinel-cpp VERSION 1.0.1 LANGUAGES C CXX) 4 | 5 | set(CMAKE_CXX_STANDARD 14) 6 | 7 | set(SENTINEL_CORE_ROOT_DIR "${CMAKE_SOURCE_DIR}/../sentinel-core") 8 | 9 | set(SENTINEL_ROOT_DIR "${CMAKE_SOURCE_DIR}/..") 10 | 11 | include( ${CMAKE_SOURCE_DIR}/../cmake/common.cmake ) 12 | 13 | # basic_qps_limit 14 | add_executable(basic_qps_limit ${CMAKE_SOURCE_DIR}/../examples/sentinel-cpp/basic_qps_limit.cc) 15 | target_link_libraries(basic_qps_limit sentinel) 16 | 17 | # basic_concurrency_limit 18 | add_executable(basic_concurrency_limit ${CMAKE_SOURCE_DIR}/../examples/sentinel-cpp/basic_concurrency_limit.cc) 19 | target_link_libraries(basic_concurrency_limit sentinel) 20 | 21 | # basic_param_limit 22 | add_executable(basic_param_limit ${CMAKE_SOURCE_DIR}/../examples/sentinel-cpp/basic_param_limit.cc) 23 | target_link_libraries(basic_param_limit sentinel) 24 | 25 | # basic_system_limit 26 | add_executable(basic_system_limit ${CMAKE_SOURCE_DIR}/../examples/sentinel-cpp/basic_system_limit.cc) 27 | target_link_libraries(basic_system_limit sentinel) -------------------------------------------------------------------------------- /examples/abseil/BUILD: -------------------------------------------------------------------------------- 1 | cc_binary( 2 | name = "asbeil_string", 3 | srcs = ["abseil_string.cc"], 4 | deps = [ 5 | "@com_google_absl//absl/strings", 6 | ], 7 | ) 8 | -------------------------------------------------------------------------------- /examples/abseil/abseil_string.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "absl/strings/str_cat.h" 5 | #include "absl/strings/string_view.h" 6 | 7 | std::string Greet(absl::string_view person) { 8 | return absl::StrCat("Hello ", person); 9 | } 10 | 11 | int main(int argc, char* argv[]) { 12 | std::cout << Greet(argc < 2 ? "world" : argv[1]) << std::endl; 13 | } 14 | -------------------------------------------------------------------------------- /examples/benchmark/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | cc_binary( 4 | name = "benchmark_test", 5 | srcs = ["benchamrk_test.cc"], 6 | copts = DEFAULT_COPTS, 7 | deps = [ 8 | "//sentinel-core/public:sph_u_lib", 9 | "@com_google_benchmark//:benchmark", 10 | "//sentinel-core/log/metric:metric_log_task_lib", 11 | ], 12 | ) 13 | -------------------------------------------------------------------------------- /examples/cache/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | package(default_visibility = ["//visibility:public"]) 3 | 4 | cc_binary( 5 | name = "cache_test", 6 | srcs = ["cache_test.cc"], 7 | copts = DEFAULT_COPTS, 8 | deps = [ 9 | "//sentinel-core/param/statistic:scalable_cache_lib", 10 | "//sentinel-core/param/statistic:any_cmp_lib", 11 | "//sentinel-core/log:logger_lib", 12 | ], 13 | ) 14 | -------------------------------------------------------------------------------- /examples/fmt/BUILD: -------------------------------------------------------------------------------- 1 | cc_binary( 2 | name = "fmt_test", 3 | srcs = ["fmt_test.cc"], 4 | deps = [ 5 | "@com_github_fmtlib_fmt//:fmtlib", 6 | ], 7 | ) 8 | -------------------------------------------------------------------------------- /examples/fmt/fmt_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "fmt/format.h" 5 | 6 | int main() { 7 | std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy"); 8 | std::cout << s << std::endl; 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /examples/gtest/BUILD: -------------------------------------------------------------------------------- 1 | cc_test( 2 | name = "hello_test", 3 | srcs = ["hello_test.cc"], 4 | deps = [ 5 | "@com_google_googletest//:gtest_main", 6 | ], 7 | ) 8 | -------------------------------------------------------------------------------- /examples/gtest/hello_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "gtest/gtest.h" 4 | 5 | TEST(HelloTest, Basic) { EXPECT_EQ("Hello tester", "Hello tester"); } 6 | -------------------------------------------------------------------------------- /examples/json/BUILD: -------------------------------------------------------------------------------- 1 | cc_binary( 2 | name = "nlohmann_json_example", 3 | srcs = ["nlohmann_json_example.cc"], 4 | deps = [ 5 | "//third_party/nlohmann:nlohmann_json_lib", 6 | ], 7 | ) 8 | -------------------------------------------------------------------------------- /examples/json/nlohmann_json_example.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "third_party/nlohmann/json.hpp" 5 | 6 | int main() { 7 | try { 8 | auto j2 = nlohmann::json::parse("sa"); 9 | } catch (std::exception& ex) { 10 | std::cerr << "Exception: " << ex.what() << std::endl; 11 | } 12 | 13 | // create a JSON array 14 | auto j3 = nlohmann::json::parse("{ \"happy\": true, \"pi\": 3.141 }"); 15 | auto c = j3["pi"]; 16 | if (c.is_number()) { 17 | int d = static_cast(c); 18 | std::cout << d << std::endl; 19 | } 20 | 21 | std::cout << typeid(c).name() << std::endl; 22 | return 0; 23 | } -------------------------------------------------------------------------------- /examples/libevent/BUILD: -------------------------------------------------------------------------------- 1 | cc_binary( 2 | name = "libevent_echosrv1", 3 | srcs = ["libevent_echosrv1.c"], 4 | deps = [ 5 | "//:libevent", 6 | ], 7 | ) 8 | -------------------------------------------------------------------------------- /examples/log/BUILD: -------------------------------------------------------------------------------- 1 | cc_binary( 2 | name = "log_test", 3 | srcs = ["log_test.cc"], 4 | deps = [ 5 | "@com_github_gabime_spdlog//:spdlog", 6 | ], 7 | ) 8 | -------------------------------------------------------------------------------- /examples/log/log_test.cc: -------------------------------------------------------------------------------- 1 | #include "spdlog/spdlog.h" 2 | int main() { 3 | spdlog::info("Welcome to spdlog!"); 4 | spdlog::error("Some error message with arg: {}", 1); 5 | 6 | spdlog::warn("Easy padding in numbers like {:08d}", 12); 7 | spdlog::critical( 8 | "Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); 9 | spdlog::info("Support for floats {:03.2f}", 1.23456); 10 | spdlog::info("Positional args are {1} {0}..", "too", "supported"); 11 | spdlog::info("{:<30}", "left aligned"); 12 | 13 | spdlog::set_level(spdlog::level::debug); // Set global log level to debug 14 | spdlog::debug("This message should be displayed.."); 15 | 16 | // change log pattern 17 | spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v"); 18 | 19 | // Compile time log levels 20 | // define SPDLOG_ACTIVE_LEVEL to desired level 21 | SPDLOG_TRACE("Some trace message with param {}", {}); 22 | SPDLOG_DEBUG("Some debug message"); 23 | 24 | // Set the default logger to file logger 25 | // auto file_logger = spdlog::basic_logger_mt("basic_logger", 26 | // "logs/basic.txt"); spdlog::set_default_logger(file_logger); 27 | } 28 | -------------------------------------------------------------------------------- /examples/sentinel-cpp/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | # https://docs.bazel.build/versions/master/be/c-cpp.html#cc_binary 6 | cc_binary( 7 | name = "sentinel_basic_qps_limit", 8 | srcs = ["basic_qps_limit.cc"], 9 | copts = DEFAULT_COPTS, 10 | deps = [ 11 | "//sentinel-core/public:sph_u_lib", 12 | "//sentinel-core/log/metric:metric_log_task_lib", 13 | "//sentinel-core/transport/command:http_command_center_init_target", 14 | ], 15 | ) 16 | 17 | cc_binary( 18 | name = "sentinel_basic_concurrency_limit", 19 | srcs = ["basic_concurrency_limit.cc"], 20 | copts = DEFAULT_COPTS, 21 | deps = [ 22 | "//sentinel-core/public:sph_u_lib", 23 | "//sentinel-core/log/metric:metric_log_task_lib", 24 | "//sentinel-core/transport/command:http_command_center_init_target", 25 | ], 26 | ) 27 | 28 | # https://docs.bazel.build/versions/master/be/c-cpp.html#cc_binary 29 | cc_binary( 30 | name = "sentinel_basic_system_limit", 31 | srcs = ["basic_system_limit.cc"], 32 | copts = DEFAULT_COPTS, 33 | deps = [ 34 | "//sentinel-core/public:sph_u_lib", 35 | "//sentinel-core/log/metric:metric_log_task_lib", 36 | "//sentinel-core/transport/command:http_command_center_init_target", 37 | ], 38 | ) 39 | 40 | cc_binary( 41 | name = "sentinel_basic_param_limit", 42 | srcs = ["basic_param_limit.cc"], 43 | copts = DEFAULT_COPTS, 44 | deps = [ 45 | "//sentinel-core/public:sph_u_lib", 46 | "//sentinel-core/log/metric:metric_log_task_lib", 47 | "//sentinel-core/transport/command:http_command_center_init_target", 48 | ], 49 | ) -------------------------------------------------------------------------------- /examples/tbb/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | package(default_visibility = ["//visibility:public"]) 3 | 4 | cc_binary( 5 | name = "tbb_test", 6 | srcs = ["tbb_test.cc"], 7 | # srcs = select({ 8 | # "//bazel:is_android": [], 9 | # "//bazel:is_wsl": [ "tbb_test.cc" ], 10 | # "//conditions:default": [ "tbb_test.cc" ], 11 | # }), 12 | copts = DEFAULT_COPTS, 13 | deps = select({ 14 | "//bazel:is_osx": [ 15 | "//sentinel-core/log:logger_lib", 16 | "@com_github_libtbb_osx//:tbb_osx", 17 | ], 18 | "//conditions:default": [ 19 | "//sentinel-core/log:logger_lib", 20 | "@com_github_libtbb//:tbb", 21 | ], 22 | }), 23 | ) 24 | -------------------------------------------------------------------------------- /examples/tbb/tbb_test.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include "sentinel-core/log/logger.h" 7 | #include "tbb/concurrent_hash_map.h" 8 | 9 | constexpr int NUM_THREADS = 10000; 10 | 11 | class Stu { 12 | public: 13 | int id; 14 | std::string name; 15 | ~Stu() { std::cout << "Destructor" << std::endl; } 16 | }; 17 | tbb::concurrent_hash_map> stuMap; 18 | 19 | int main() { 20 | Sentinel::Log::Logger::InitDefaultLogger(); 21 | std::cout << "loop begin\n"; 22 | 23 | decltype(stuMap)::accessor ac; 24 | if (stuMap.insert(ac, std::make_pair<>(1, nullptr))) { 25 | ac->second = std::make_unique(); 26 | std::cout << stuMap.size() << std::endl; 27 | } 28 | ac.release(); 29 | decltype(stuMap)::accessor ac2; 30 | stuMap.insert(ac2, std::make_pair<>(1, std::make_unique())); 31 | 32 | std::cout << "===== END =====" << stuMap.size() << std::endl; 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /format.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | CMD=clang-format-8 4 | $CMD -version 5 | $CMD -i -style=Google $(git ls-files|grep -E ".*\.(cc|h)$") 6 | CHANGED="$(git ls-files --modified)" 7 | if [[ ! -z "$CHANGED" ]]; then 8 | echo "The following files have changes due to incrrect format:" 9 | echo "$CHANGED" 10 | echo "please use format.sh script fix it" 11 | exit 1 12 | else 13 | echo "No changes." 14 | fi 15 | -------------------------------------------------------------------------------- /sentinel-core/BUILD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba/sentinel-cpp/36871db9cc0ca76b9bdf666f0a99f41bb026abfc/sentinel-core/BUILD -------------------------------------------------------------------------------- /sentinel-core/circuitbreaker/circuit_breaker.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "sentinel-core/circuitbreaker/circuit_breaker.h" 5 | #include "sentinel-core/utils/time_utils.h" 6 | 7 | namespace Sentinel { 8 | namespace CircuitBreaker { 9 | 10 | State AbstractCircuitBreaker::CurrentState() { return current_state_.load(); } 11 | 12 | const Rule& AbstractCircuitBreaker::GetRule() const { return rule_; } 13 | 14 | bool AbstractCircuitBreaker::RetryTimeoutArrived() { 15 | return Utils::TimeUtils::CurrentTimeMillis().count() >= next_retry_timestamp_; 16 | } 17 | void AbstractCircuitBreaker::UpdateNextRetryTimestamp() { 18 | this->next_retry_timestamp_ = 19 | Utils::TimeUtils::CurrentTimeMillis().count() + retry_timeout_ms_; 20 | } 21 | 22 | bool AbstractCircuitBreaker::FromCloseToOpen(double snapshot) { 23 | auto expected = State::kClosed; 24 | if (current_state_.compare_exchange_strong(expected, State::kOpen)) { 25 | UpdateNextRetryTimestamp(); 26 | return true; 27 | } 28 | return false; 29 | } 30 | 31 | bool AbstractCircuitBreaker::FromOpenToHalfOpen() { 32 | auto expected = State::kOpen; 33 | return current_state_.compare_exchange_strong(expected, State::kHalfOpen); 34 | } 35 | 36 | bool AbstractCircuitBreaker::FromHalfOpenToOpen(double snapshot) { 37 | auto expected = State::kHalfOpen; 38 | if (current_state_.compare_exchange_strong(expected, State::kOpen)) { 39 | UpdateNextRetryTimestamp(); 40 | return true; 41 | } 42 | return false; 43 | } 44 | 45 | bool AbstractCircuitBreaker::FromHalfOpenToClose() { 46 | auto expected = State::kHalfOpen; 47 | if (current_state_.compare_exchange_strong(expected, State::kClosed)) { 48 | Reset(); 49 | return true; 50 | } 51 | return false; 52 | } 53 | 54 | } // namespace CircuitBreaker 55 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/circuitbreaker/circuit_breaker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "sentinel-core/circuitbreaker/rule.h" 7 | #include "sentinel-core/statistic/node/node.h" 8 | 9 | namespace Sentinel { 10 | namespace CircuitBreaker { 11 | 12 | enum class State { kClosed = 0, kOpen = 1, kHalfOpen = 2 }; 13 | 14 | class CircuitBreaker { 15 | public: 16 | CircuitBreaker() = default; 17 | virtual ~CircuitBreaker() = default; 18 | 19 | virtual const Rule& GetRule() const = 0; 20 | virtual State CurrentState() = 0; 21 | virtual bool TryPass(Stat::NodeSharedPtr& node) = 0; 22 | virtual void Reset() = 0; 23 | virtual void RecordComplete(int64_t rt, const std::string& error) = 0; 24 | }; 25 | 26 | using CircuitBreakerSharedPtr = std::shared_ptr; 27 | 28 | class AbstractCircuitBreaker : public CircuitBreaker { 29 | public: 30 | explicit AbstractCircuitBreaker(const Rule& rule) 31 | : rule_(rule), retry_timeout_ms_(rule.retry_timeout_sec() * 1000) {} 32 | virtual ~AbstractCircuitBreaker() = default; 33 | 34 | State CurrentState() override; 35 | const Rule& GetRule() const override; 36 | 37 | protected: 38 | bool RetryTimeoutArrived(); 39 | void UpdateNextRetryTimestamp(); 40 | 41 | bool FromCloseToOpen(double snapshot); 42 | bool FromOpenToHalfOpen(); 43 | bool FromHalfOpenToOpen(double snapshot); 44 | bool FromHalfOpenToClose(); 45 | 46 | const Rule rule_; 47 | const int32_t retry_timeout_ms_; 48 | 49 | std::atomic current_state_{State::kClosed}; 50 | int64_t next_retry_timestamp_ = 0; 51 | }; 52 | 53 | } // namespace CircuitBreaker 54 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/circuitbreaker/rule.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "sentinel-core/circuitbreaker/rule.h" 4 | 5 | #include "absl/strings/str_format.h" 6 | 7 | namespace Sentinel { 8 | namespace CircuitBreaker { 9 | 10 | bool CircuitBreaker::Rule::operator==(const CircuitBreaker::Rule& rule) const { 11 | return resource_ == rule.resource() && threshold_ == rule.threshold() && 12 | strategy_ == rule.strategy() && 13 | retry_timeout_sec_ == rule.retry_timeout_sec() && 14 | min_request_amount_ == rule.min_request_amount() && 15 | stat_interval_ms_ == rule.stat_interval_ms() && 16 | max_allowed_rt_ == rule.max_allowed_rt(); 17 | } 18 | 19 | std::string CircuitBreaker::Rule::ToString() const { 20 | return absl::StrFormat( 21 | "CircuitBreakerRule{resource=%s, strategy=%d, threshold=%.2f, " 22 | "retry_timeout_sec=%d, min_request_amount=%d, stat_interval_ms=%d, " 23 | "max_allowed_rt=%d}", 24 | resource_, static_cast(strategy_), threshold_, retry_timeout_sec_, 25 | min_request_amount_, stat_interval_ms_, max_allowed_rt_); 26 | } 27 | 28 | } // namespace CircuitBreaker 29 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/circuitbreaker/slot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sentinel-core/slot/base/rule_checker_slot.h" 4 | #include "sentinel-core/slot/base/stats_slot.h" 5 | 6 | namespace Sentinel { 7 | namespace CircuitBreaker { 8 | 9 | constexpr auto kCheckerSlotName = "CircuitBreakerCheckerSlot"; 10 | constexpr auto kCompleteStatSlotName = "CircuitBreakerCompleteStatSlot"; 11 | 12 | class CheckerSlot : public Slot::RuleCheckerSlot { 13 | public: 14 | CheckerSlot() = default; 15 | virtual ~CheckerSlot() = default; 16 | 17 | Sentinel::Slot::TokenResultSharedPtr Entry( 18 | const EntrySharedPtr& entry, Stat::NodeSharedPtr& node, int count, 19 | int flag, const std::vector& params) override; 20 | void Exit(const EntrySharedPtr& entry, int count, 21 | const std::vector& params) override; 22 | const std::string& Name() const override { return name_; }; 23 | 24 | private: 25 | const std::string name_{kCheckerSlotName}; 26 | }; 27 | 28 | class CompleteStatSlot : public Slot::StatsSlot { 29 | public: 30 | CompleteStatSlot() = default; 31 | virtual ~CompleteStatSlot() = default; 32 | 33 | const std::string& Name() const override { return name_; }; 34 | Sentinel::Slot::TokenResultSharedPtr Entry( 35 | const EntrySharedPtr& entry, 36 | /*const*/ Stat::NodeSharedPtr& node, int count, int flag, 37 | const std::vector& params) override; 38 | void Exit(const EntrySharedPtr& entry, int count, 39 | const std::vector& params) override; 40 | 41 | private: 42 | const std::string name_{kCompleteStatSlotName}; 43 | }; 44 | 45 | } // namespace CircuitBreaker 46 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/common/constants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Sentinel { 4 | namespace Constants { 5 | 6 | static constexpr int kDefaultSampleCount = 2; 7 | static constexpr int kDefaultIntervalMs = 1000; 8 | 9 | static constexpr const char* kLimitOriginDefault = "default"; 10 | static constexpr const char* kLimitOriginOther = "other"; 11 | 12 | static constexpr const char* kDefaultContextName = "sentinel_default_context"; 13 | 14 | static constexpr int kMaxAllowedRt = 4900; 15 | static constexpr int kMaxResourceSize = 10000; 16 | static constexpr int kMaxTagSize = 1000; 17 | 18 | }; // namespace Constants 19 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/common/entry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "sentinel-core/common/entry_context.h" 8 | #include "sentinel-core/common/resource_wrapper.h" 9 | #include "sentinel-core/utils/time_utils.h" 10 | 11 | namespace Sentinel { 12 | 13 | class Entry { 14 | public: 15 | explicit Entry(const ResourceWrapperSharedPtr& resource, 16 | const EntryContextSharedPtr& context) 17 | : resource_(resource), 18 | context_(context), 19 | create_time_(Utils::TimeUtils::CurrentTimeMillis()) {} 20 | 21 | virtual ~Entry() = default; 22 | 23 | friend class EntryResult; 24 | friend class SphU; 25 | 26 | ResourceWrapperSharedPtr resource() const { return resource_; } 27 | std::chrono::milliseconds create_time() const { return create_time_; } 28 | EntryContextSharedPtr context() const { return context_; } 29 | Stat::NodeSharedPtr cur_node() const { return cur_node_; } 30 | int64_t rt() const { return rt_; } 31 | std::vector params() const { return params_; } 32 | bool exited() const { return exited_; } 33 | std::string error() const { return error_; } 34 | bool HasError() const { return !error_.empty(); }; 35 | bool HasBlockError() const { return !block_error_.empty(); }; 36 | 37 | void set_rt(int64_t rt) { rt_ = rt; } 38 | void set_error(const std::string& message) { error_ = message; } 39 | void set_block_error(const std::string& message) { block_error_ = message; } 40 | void set_cur_node(const Stat::NodeSharedPtr& node) { cur_node_ = node; } 41 | void set_params(const std::vector&& params) { params_ = params; } 42 | 43 | private: 44 | const ResourceWrapperSharedPtr resource_; 45 | EntryContextSharedPtr context_; 46 | const std::chrono::milliseconds create_time_; 47 | 48 | bool exited_{false}; 49 | int64_t rt_{-1}; 50 | std::string error_{}; 51 | std::string block_error_{}; 52 | Stat::NodeSharedPtr cur_node_; 53 | std::vector params_; 54 | }; 55 | 56 | using EntrySharedPtr = std::shared_ptr; 57 | 58 | } // namespace Sentinel 59 | -------------------------------------------------------------------------------- /sentinel-core/common/entry_context.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "sentinel-core/common/entry_context.h" 4 | 5 | namespace Sentinel {} // namespace Sentinel 6 | -------------------------------------------------------------------------------- /sentinel-core/common/entry_context.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "sentinel-core/slot/base/token_result.h" 7 | #include "sentinel-core/statistic/node/node.h" 8 | 9 | namespace Sentinel { 10 | 11 | class EntryContext { 12 | public: 13 | explicit EntryContext(const std::string& name) : EntryContext(name, "") {} 14 | EntryContext(const std::string& name, const std::string& tag) 15 | : name_(name), tag_(tag) {} 16 | 17 | const std::string& name() const { return name_; }; 18 | const std::string& tag() const { return tag_; }; 19 | Stat::NodeSharedPtr tag_node() { return tag_node_; } 20 | 21 | const Slot::TokenResultSharedPtr& last_token_result() const { 22 | return last_token_result_; 23 | } 24 | /** 25 | * Users should not invoke this. 26 | */ 27 | void set_last_token_result(const Slot::TokenResultSharedPtr& r) { 28 | last_token_result_ = r; 29 | } 30 | void set_tag_node(Stat::NodeSharedPtr& node) { tag_node_ = node; } 31 | 32 | private: 33 | const std::string name_; 34 | // Maybe multiple tags in the future, using vector instead of string. 35 | const std::string tag_; 36 | Stat::NodeSharedPtr tag_node_; 37 | 38 | Slot::TokenResultSharedPtr last_token_result_; 39 | }; 40 | 41 | using EntryContextSharedPtr = std::shared_ptr; 42 | 43 | } // namespace Sentinel 44 | -------------------------------------------------------------------------------- /sentinel-core/common/entry_node.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba/sentinel-cpp/36871db9cc0ca76b9bdf666f0a99f41bb026abfc/sentinel-core/common/entry_node.h -------------------------------------------------------------------------------- /sentinel-core/common/entry_result.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/common/entry_result.h" 2 | #include "sentinel-core/slot/global_slot_chain.h" 3 | 4 | namespace Sentinel { 5 | 6 | bool EntryResult::IsBlocked() const { return blocked_reason_.has_value(); } 7 | 8 | bool EntryResult::Exit() { return Exit(1); } 9 | 10 | bool EntryResult::Exit(int count) { 11 | if (entry_ == nullptr) { 12 | return false; 13 | } 14 | const std::vector params = entry_->params(); 15 | if (!entry_->exited()) { 16 | Slot::SlotChainSharedPtr chain = Slot::GetGlobalSlotChain(); 17 | if (chain != nullptr) { 18 | // NOTE: keep consistent with exit operation in SphU::Entry when blocked. 19 | chain->Exit(entry_, count, params); 20 | } 21 | entry_->exited_ = true; 22 | return true; 23 | } 24 | return false; 25 | } 26 | 27 | void EntryResult::SetError(const std::string& err) { 28 | if (entry_ != nullptr) { 29 | entry_->set_error(err); 30 | } 31 | } 32 | 33 | } // namespace Sentinel 34 | -------------------------------------------------------------------------------- /sentinel-core/common/entry_result.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "absl/types/optional.h" 7 | #include "sentinel-core/common/entry_result.h" 8 | #include "sentinel-core/slot/global_slot_chain.h" 9 | 10 | namespace Sentinel { 11 | 12 | class EntryResult { 13 | public: 14 | explicit EntryResult(const EntrySharedPtr& entry) : entry_(entry) {} 15 | explicit EntryResult(const std::string& reason) 16 | : entry_(nullptr), blocked_reason_(reason) {} 17 | ~EntryResult() = default; 18 | 19 | EntrySharedPtr entry() const { return entry_; }; 20 | absl::optional blocked_reason() const { 21 | return blocked_reason_; 22 | }; 23 | 24 | bool IsBlocked() const; 25 | bool Exit(); 26 | bool Exit(int count); 27 | bool Exit(int count, const std::vector& params); 28 | 29 | void SetError(const std::string& err); 30 | 31 | private: 32 | const EntrySharedPtr entry_; 33 | const absl::optional blocked_reason_; 34 | }; 35 | 36 | using EntryResultPtr = std::unique_ptr; 37 | 38 | } // namespace Sentinel 39 | -------------------------------------------------------------------------------- /sentinel-core/common/entry_type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Sentinel { 4 | enum class EntryType { IN, OUT }; 5 | 6 | } // namespace Sentinel 7 | -------------------------------------------------------------------------------- /sentinel-core/common/global_status.cc: -------------------------------------------------------------------------------- 1 | namespace Sentinel { 2 | namespace GlobalStatus { 3 | 4 | bool activated = true; 5 | 6 | }; // namespace GlobalStatus 7 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/common/global_status.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Sentinel { 4 | namespace GlobalStatus { 5 | 6 | extern bool activated; 7 | 8 | }; // namespace GlobalStatus 9 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/common/resource_wrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "absl/types/any.h" 7 | #include "sentinel-core/common/entry_type.h" 8 | 9 | namespace Sentinel { 10 | 11 | class ResourceWrapper; 12 | 13 | using ResourceWrapperSharedPtr = std::shared_ptr; 14 | class ResourceWrapper { 15 | public: 16 | virtual ~ResourceWrapper() = default; 17 | 18 | virtual const std::string& name() const = 0; 19 | virtual EntryType entry_type() const = 0; 20 | }; 21 | 22 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/common/rule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/common/constants.h" 6 | 7 | namespace Sentinel { 8 | 9 | class Rule { 10 | public: 11 | Rule() = default; 12 | virtual ~Rule() = default; 13 | 14 | static bool LimitOriginEquals(const std::string& lhs, 15 | const std::string& rhs) { 16 | if (lhs.empty()) { 17 | return rhs.empty() || rhs == Constants::kLimitOriginDefault; 18 | } else if (lhs == Constants::kLimitOriginDefault) { 19 | return rhs.empty() || rhs == Constants::kLimitOriginDefault; 20 | } 21 | return lhs == rhs; 22 | } 23 | }; 24 | 25 | } // namespace Sentinel 26 | -------------------------------------------------------------------------------- /sentinel-core/common/string_resource_wrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/common/resource_wrapper.h" 6 | 7 | namespace Sentinel { 8 | class StringResourceWrapper : public ResourceWrapper { 9 | public: 10 | StringResourceWrapper(const std::string& name, EntryType type) 11 | : name_(name), entry_type_(type) {} 12 | virtual ~StringResourceWrapper() = default; 13 | 14 | const std::string& name() const override { return name_; } 15 | EntryType entry_type() const override { return entry_type_; } 16 | 17 | private: 18 | std::string name_; 19 | EntryType entry_type_; 20 | }; 21 | 22 | } // namespace Sentinel 23 | -------------------------------------------------------------------------------- /sentinel-core/common/tracer.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "sentinel-core/common/tracer.h" 4 | #include "sentinel-core/statistic/node/node.h" 5 | 6 | namespace Sentinel { 7 | 8 | void Tracer::Trace(const EntrySharedPtr entry, const std::string&, int count) { 9 | if (entry == nullptr || count <= 0) { 10 | return; 11 | } 12 | // TODO: check BlockException? 13 | Stat::NodeSharedPtr node = entry->cur_node(); 14 | if (node != nullptr) { 15 | node->AddExceptionRequest(count); 16 | } 17 | } 18 | 19 | void Tracer::Trace(const EntrySharedPtr entry, const std::string& message) { 20 | Tracer::Trace(entry, message, 1); 21 | } 22 | 23 | } // namespace Sentinel 24 | -------------------------------------------------------------------------------- /sentinel-core/common/tracer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/common/entry.h" 6 | 7 | namespace Sentinel { 8 | 9 | class Tracer { 10 | public: 11 | Tracer() = delete; 12 | 13 | static void Trace(const EntrySharedPtr entry, const std::string& message); 14 | static void Trace(const EntrySharedPtr entry, const std::string& message, 15 | int count); 16 | }; 17 | 18 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/common/tracer_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "gmock/gmock.h" 4 | #include "gtest/gtest.h" 5 | 6 | #include "sentinel-core/common/entry.h" 7 | #include "sentinel-core/common/string_resource_wrapper.h" 8 | #include "sentinel-core/common/tracer.h" 9 | #include "sentinel-core/test/mock/statistic/node/mock.h" 10 | 11 | using testing::_; 12 | using testing::InSequence; 13 | using testing::Return; 14 | 15 | namespace Sentinel { 16 | 17 | TEST(TracerTest, TraceExceptionTest) { 18 | { 19 | auto node = std::make_shared(); 20 | int n = 10; 21 | 22 | EXPECT_CALL(*node.get(), AddExceptionRequest(n)).Times(1); 23 | 24 | EntrySharedPtr entry = std::make_shared( 25 | std::make_shared("abc", EntryType::IN), nullptr); 26 | entry->set_cur_node(node); 27 | 28 | Tracer::Trace(entry, "some_exception", n); 29 | } 30 | } 31 | 32 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/config/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | cc_library( 6 | name = "config_constants", 7 | srcs = [ 8 | "config_constants.h", 9 | ], 10 | copts = DEFAULT_COPTS, 11 | ) 12 | 13 | cc_library( 14 | name = "local_config_lib", 15 | srcs = [ 16 | "local_config.h", 17 | "local_config.cc", 18 | ], 19 | copts = DEFAULT_COPTS, 20 | deps = [ 21 | ":config_constants", 22 | "//sentinel-core/init:init_target_interface", 23 | "//sentinel-core/log:logger_lib", 24 | "@com_google_absl//absl/strings", 25 | ] 26 | ) 27 | 28 | cc_test( 29 | name = "local_config_unittests", 30 | srcs = [ 31 | "local_config_test.cc", 32 | ], 33 | copts = TEST_COPTS, 34 | deps = [ 35 | ":local_config_lib", 36 | "@com_google_googletest//:gtest_main", 37 | ] 38 | ) 39 | -------------------------------------------------------------------------------- /sentinel-core/config/config_constants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace Sentinel { 6 | namespace Config { 7 | 8 | const auto kUnknownAppName = "unknown_cpp_service"; 9 | constexpr uint32_t kDefaultAppType = 0; 10 | constexpr auto kDefaultCharset = "UTF-8"; 11 | constexpr uint32_t kDefaultSingleMetricFileSize = 1024 * 1024 * 50; 12 | const uint32_t kDefaultTotalMetricFileCount = 6; 13 | const uint32_t kDefaultWarmUpColdFactor = 3; 14 | const uint32_t kDefaultStatisticMaxRt = 4900; 15 | 16 | namespace Env { 17 | 18 | constexpr auto kAppNameKey = "CSP_SENTINEL_APP_NAME"; 19 | constexpr auto kAppTypeKey = "CSP_SENTINEL_APP_TYPE"; 20 | constexpr auto kCharsetKey = "CSP_SENTINEL_CHARSET"; 21 | constexpr auto kSingleMetricFileSizeKey = 22 | "CSP_SENTINEL_METRIC_FILE_SINGLE_SIZE"; 23 | constexpr auto kTotalMetricFileCountKey = 24 | "CSP_SENTINEL_METRIC_FILE_TOTAL_COUNT"; 25 | constexpr auto kWarmUpColdFactorKey = "CSP_SENTINEL_FLOW_WARMUP_COLD_FACTOR"; 26 | constexpr auto kStatisticMaxRtKey = "CSP_SENTINEL_STATISTIC_MAX_RT"; 27 | 28 | } // namespace Env 29 | 30 | namespace Args { 31 | 32 | constexpr auto kAppNameKey = "project.name"; 33 | constexpr auto kAppTypeKey = "csp.sentinel.app.type"; 34 | constexpr auto kCharsetKey = "csp.sentinel.charset"; 35 | constexpr auto kSingleMetricFileSizeKey = 36 | "csp.sentinel.metric.file.single.size"; 37 | constexpr auto kTotalMetricFileCountKey = 38 | "csp.sentinel.metric.file.total.count"; 39 | constexpr auto kWarmUpColdFactorKey = "csp.sentinel.flow.cold.factor"; 40 | constexpr auto kStatisticMaxRtKey = "csp.sentinel.statistic.max.rt"; 41 | 42 | } // namespace Args 43 | 44 | } // namespace Config 45 | } // namespace Sentinel 46 | -------------------------------------------------------------------------------- /sentinel-core/config/local_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "sentinel-core/init/init_target.h" 7 | 8 | namespace Sentinel { 9 | namespace Config { 10 | 11 | class LocalConfig { 12 | public: 13 | ~LocalConfig() = default; 14 | 15 | static LocalConfig& GetInstance() { 16 | static LocalConfig* instance = new LocalConfig(); 17 | return *instance; 18 | } 19 | 20 | const std::string GetConfig(const std::string& key) const; 21 | void SetConfig(const std::string& key, const std::string& value); 22 | void SetConfigIfNotExists(const std::string& key, const std::string& value); 23 | void RemoveConfig(const std::string& key); 24 | 25 | int32_t GetInt32(const std::string& key, int32_t default_value) const; 26 | int64_t GetInt64(const std::string& key, int64_t default_value) const; 27 | 28 | const std::string& app_name() const { return app_name_; } 29 | void set_app_name(const std::string& app_name) { app_name_ = app_name; } 30 | 31 | int32_t WarmUpColdFactor() const; 32 | int32_t StatisticMaxRt() const; 33 | int32_t TotalMetricFileCount() const; 34 | int64_t SingleMetricFileSize() const; 35 | const std::string Charset() const; 36 | 37 | private: 38 | std::unordered_map config_map_; 39 | std::string app_name_; 40 | 41 | LocalConfig(); 42 | 43 | void ResolveAppName(); 44 | void Initialize(); 45 | }; 46 | 47 | } // namespace Config 48 | } // namespace Sentinel 49 | -------------------------------------------------------------------------------- /sentinel-core/config/local_config_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "gmock/gmock.h" 5 | #include "gtest/gtest.h" 6 | 7 | #include "sentinel-core/config/config_constants.h" 8 | #include "sentinel-core/config/local_config.h" 9 | 10 | namespace Sentinel { 11 | namespace Config { 12 | 13 | TEST(LocalConfigTest, TestResolveNormalAppName) { 14 | auto app_name = "test_app"; 15 | setenv(Env::kAppNameKey, app_name, 1); 16 | LocalConfig config = LocalConfig::GetInstance(); 17 | EXPECT_EQ(app_name, config.app_name()); 18 | unsetenv(Env::kAppNameKey); 19 | } 20 | 21 | TEST(LocalConfigTest, TestGetIntOfInvalidValue) { 22 | LocalConfig config = LocalConfig::GetInstance(); 23 | constexpr auto key = "some_key_bad"; 24 | config.SetConfig(key, "a32"); 25 | constexpr int32_t d = 32; 26 | EXPECT_EQ(d, config.GetInt32(key, d)); 27 | } 28 | 29 | TEST(LocalConfigTest, TestGetIntOfNormalValue) { 30 | LocalConfig config = LocalConfig::GetInstance(); 31 | constexpr auto key = "some_key_good"; 32 | config.SetConfig(key, "64"); 33 | constexpr int32_t d = 32; 34 | EXPECT_EQ(64, config.GetInt32(key, d)); 35 | } 36 | 37 | } // namespace Config 38 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/flow/default_traffic_shaping_calculator.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/flow/default_traffic_shaping_calculator.h" 2 | 3 | namespace Sentinel { 4 | namespace Flow { 5 | 6 | double DefaultTrafficShapingCalculator::CalculateAllowedTokens( 7 | const Stat::NodeSharedPtr&, int, int) { 8 | return threshold_; 9 | } 10 | 11 | } // namespace Flow 12 | } // namespace Sentinel 13 | -------------------------------------------------------------------------------- /sentinel-core/flow/default_traffic_shaping_calculator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sentinel-core/flow/traffic_shaping_calculator.h" 4 | 5 | namespace Sentinel { 6 | namespace Flow { 7 | 8 | class DefaultTrafficShapingCalculator : public TrafficShapingCalculator { 9 | public: 10 | DefaultTrafficShapingCalculator(double t) : threshold_(t) {} 11 | virtual ~DefaultTrafficShapingCalculator() = default; 12 | 13 | double CalculateAllowedTokens(const Stat::NodeSharedPtr& node, 14 | int acquire_count, int flag) override; 15 | 16 | private: 17 | const double threshold_; 18 | }; 19 | 20 | } // namespace Flow 21 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/flow/default_traffic_shaping_checker.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/flow/default_traffic_shaping_checker.h" 2 | #include "sentinel-core/flow/flow_rule_constants.h" 3 | 4 | namespace Sentinel { 5 | namespace Flow { 6 | 7 | Slot::TokenResultSharedPtr DefaultTrafficShapingChecker::DoCheck( 8 | const Stat::NodeSharedPtr& node, int acquire_count, double threshold) { 9 | double cur_pass = 0; 10 | if (node != nullptr) { 11 | cur_pass = mode_ == (int)FlowMetricType::kThreadCount ? node->CurThreadNum() 12 | : node->PassQps(); 13 | } 14 | if (cur_pass + acquire_count > threshold) { 15 | return Slot::TokenResult::Blocked("FlowException"); 16 | } 17 | return Slot::TokenResult::Ok(); 18 | } 19 | 20 | } // namespace Flow 21 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/flow/default_traffic_shaping_checker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sentinel-core/flow/flow_rule_constants.h" 4 | #include "sentinel-core/flow/traffic_shaping_checker.h" 5 | 6 | namespace Sentinel { 7 | namespace Flow { 8 | 9 | class DefaultTrafficShapingChecker : public TrafficShapingChecker { 10 | public: 11 | explicit DefaultTrafficShapingChecker(int mode) : mode_(mode) {} 12 | explicit DefaultTrafficShapingChecker(FlowMetricType mode) 13 | : mode_((int)mode) {} 14 | virtual ~DefaultTrafficShapingChecker() = default; 15 | 16 | Slot::TokenResultSharedPtr DoCheck(const Stat::NodeSharedPtr& node, 17 | int acquire_count, 18 | double threshold) override; 19 | 20 | private: 21 | const int mode_; 22 | }; 23 | 24 | } // namespace Flow 25 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/flow/flow_rule.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "sentinel-core/flow/flow_rule.h" 4 | 5 | #include "absl/strings/str_format.h" 6 | 7 | namespace Sentinel { 8 | namespace Flow { 9 | 10 | bool FlowRule::operator==(const FlowRule& rule) const { 11 | return resource_ == rule.resource() && 12 | Rule::LimitOriginEquals(limit_origin_, rule.limit_origin()) && 13 | metric_type_ == rule.metric_type() && count_ == rule.count() && 14 | strategy_ == rule.strategy() && ref_resource_ == rule.ref_resource() && 15 | control_behavior_ == rule.control_behavior() && 16 | warm_up_period_sec_ == rule.warm_up_period_sec() && 17 | max_queueing_time_ms_ == rule.max_queueing_time_ms() && 18 | cluster_mode_ == rule.cluster_mode(); 19 | } 20 | 21 | std::string FlowRule::ToString() const { 22 | return absl::StrFormat( 23 | "FlowRule{resource=%s, limit_origin=%s, metric_type=%d, count=%.2f, " 24 | "strategy=%d, ref_resource=%s, control_behavior=%d, " 25 | "warm_up_period_sec=%d, max_queueing_time_ms=%d, cluster_mode=%d}", 26 | resource_, limit_origin_, static_cast(metric_type_), count_, 27 | static_cast(strategy_), ref_resource_, 28 | static_cast(control_behavior_), warm_up_period_sec_, 29 | max_queueing_time_ms_, cluster_mode_); 30 | } 31 | 32 | } // namespace Flow 33 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/flow/flow_rule_checker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sentinel-core/common/entry.h" 4 | #include "sentinel-core/flow/flow_rule.h" 5 | #include "sentinel-core/slot/base/token_result.h" 6 | 7 | namespace Sentinel { 8 | namespace Flow { 9 | 10 | class FlowRuleChecker { 11 | public: 12 | FlowRuleChecker() = default; 13 | ~FlowRuleChecker() = default; 14 | 15 | Slot::TokenResultSharedPtr CanPassCheck(const FlowRule& rule, 16 | const EntrySharedPtr& entry, 17 | const Stat::NodeSharedPtr& node, 18 | int count); 19 | Slot::TokenResultSharedPtr CanPassCheck(const FlowRule& rule, 20 | const EntrySharedPtr& entry, 21 | const Stat::NodeSharedPtr& node, 22 | int count, int flag); 23 | 24 | private: 25 | Slot::TokenResultSharedPtr PassLocalCheck(const FlowRule& rule, 26 | const EntrySharedPtr& entry, 27 | const Stat::NodeSharedPtr& node, 28 | int count, int flag); 29 | 30 | Stat::NodeSharedPtr selectNodeByRequesterAndStrategy( 31 | const FlowRule& rule, const EntrySharedPtr& entry, 32 | const Stat::NodeSharedPtr& node); 33 | 34 | Stat::NodeSharedPtr SelectNodeByRelStrategy(const FlowRule& rule, 35 | const EntrySharedPtr& entry, 36 | const Stat::NodeSharedPtr& node); 37 | bool IsValidTag(const std::string& tag); 38 | }; 39 | 40 | } // namespace Flow 41 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/flow/flow_rule_constants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Sentinel { 4 | namespace Flow { 5 | 6 | enum class FlowMetricType { 7 | kThreadCount = 0, 8 | kQps = 1 // default mode 9 | }; 10 | 11 | enum class FlowRelationStrategy { 12 | kDirect = 0, // default relation strategy 13 | kAssociatedResource = 1, 14 | kInvocationChainEntrance = 2 15 | }; 16 | 17 | enum class FlowControlBehavior { 18 | kReject = 0, // default behavior 19 | kWarmUp = 1, 20 | kThrotting = 2, 21 | kWarmUpThrottling = 3 22 | }; 23 | 24 | } // namespace Flow 25 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/flow/flow_slot.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "sentinel-core/flow/flow_rule_manager.h" 4 | #include "sentinel-core/flow/flow_slot.h" 5 | 6 | namespace Sentinel { 7 | namespace Slot { 8 | 9 | const std::string& FlowSlot::Name() const { return name_; } 10 | 11 | TokenResultSharedPtr FlowSlot::Entry(const EntrySharedPtr& entry, 12 | Stat::NodeSharedPtr& node, int count, 13 | int flag, 14 | const std::vector& params) { 15 | std::vector rules = 16 | Flow::FlowRuleManager::GetInstance().GetRulesForResource( 17 | entry->resource()->name()); 18 | if (!rules.empty()) { 19 | for (const auto& rule : rules) { 20 | // check in order 21 | const TokenResultSharedPtr res = 22 | checker_.CanPassCheck(rule, entry, node, count, flag); 23 | if (res->status() == TokenStatus::RESULT_STATUS_BLOCKED) { 24 | return res; 25 | } 26 | if (res->status() == TokenStatus::RESULT_STATUS_SHOULD_WAIT) { 27 | if (res->wait_ms().has_value() && res->wait_ms().value().count() > 0) { 28 | std::this_thread::sleep_for(res->wait_ms().value()); 29 | continue; 30 | } 31 | } 32 | } 33 | } 34 | return TokenResult::Ok(); 35 | } 36 | 37 | void FlowSlot::Exit(const EntrySharedPtr&, int, 38 | const std::vector& params) { 39 | // Do nothing 40 | } 41 | 42 | } // namespace Slot 43 | } // namespace Sentinel 44 | -------------------------------------------------------------------------------- /sentinel-core/flow/flow_slot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "sentinel-core/flow/flow_rule_checker.h" 5 | #include "sentinel-core/slot/base/rule_checker_slot.h" 6 | 7 | namespace Sentinel { 8 | namespace Slot { 9 | 10 | constexpr auto kFlowSlotName = "FlowSlot"; 11 | 12 | class FlowSlot : public RuleCheckerSlot { 13 | public: 14 | FlowSlot() = default; 15 | virtual ~FlowSlot() = default; 16 | 17 | TokenResultSharedPtr Entry(const EntrySharedPtr& entry, 18 | Stat::NodeSharedPtr& node, int count, int flag, 19 | const std::vector& params) override; 20 | void Exit(const EntrySharedPtr& entry, int count, 21 | const std::vector& params) override; 22 | const std::string& Name() const override; 23 | 24 | private: 25 | const std::string name_{kFlowSlotName}; 26 | Flow::FlowRuleChecker checker_{}; 27 | }; 28 | 29 | } // namespace Slot 30 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/flow/throttling_traffic_shaping_checker.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "sentinel-core/flow/throttling_traffic_shaping_checker.h" 4 | #include "sentinel-core/utils/time_utils.h" 5 | 6 | namespace Sentinel { 7 | namespace Flow { 8 | 9 | Slot::TokenResultSharedPtr ThrottlingTrafficShapingChecker::DoCheck( 10 | const Stat::NodeSharedPtr&, int acquire_count, double threshold) { 11 | if (acquire_count < 0) { 12 | return Slot::TokenResult::Ok(); 13 | } 14 | if (threshold <= 0) { 15 | return Slot::TokenResult::Blocked("blocked"); 16 | } 17 | int64_t cur_time = Utils::TimeUtils::CurrentTimeMillis().count(); 18 | // Calculate the interval between every two requests. 19 | int64_t cost_time = std::round(acquire_count / threshold * 1000); 20 | // Expected pass time of this request. 21 | int64_t expected_time = cost_time + last_passed_time_.load(); 22 | if (expected_time <= cur_time) { 23 | last_passed_time_.store(cur_time); 24 | return Slot::TokenResult::Ok(); 25 | } 26 | int64_t wait_time = cost_time + last_passed_time_.load() - 27 | Utils::TimeUtils::CurrentTimeMillis().count(); 28 | if (wait_time > max_timeout_) { 29 | return Slot::TokenResult::Blocked("timeout"); 30 | } 31 | int64_t old_time = cost_time + last_passed_time_.fetch_add(cost_time); 32 | wait_time = old_time - Utils::TimeUtils::CurrentTimeMillis().count(); 33 | if (wait_time > max_timeout_) { 34 | last_passed_time_.fetch_sub(cost_time); 35 | return Slot::TokenResult::Blocked("timeout"); 36 | } 37 | if (wait_time > 0) { 38 | return Slot::TokenResult::ShouldWait(std::chrono::milliseconds(wait_time)); 39 | } 40 | return Slot::TokenResult::Ok(); 41 | } 42 | 43 | } // namespace Flow 44 | } // namespace Sentinel 45 | -------------------------------------------------------------------------------- /sentinel-core/flow/throttling_traffic_shaping_checker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/flow/flow_rule_constants.h" 6 | #include "sentinel-core/flow/traffic_shaping_checker.h" 7 | 8 | namespace Sentinel { 9 | namespace Flow { 10 | 11 | class ThrottlingTrafficShapingChecker : public TrafficShapingChecker { 12 | public: 13 | explicit ThrottlingTrafficShapingChecker(int32_t timeout) 14 | : max_timeout_(timeout) {} 15 | virtual ~ThrottlingTrafficShapingChecker() = default; 16 | 17 | Slot::TokenResultSharedPtr DoCheck(const Stat::NodeSharedPtr& node, 18 | int acquire_count, 19 | double threshold) override; 20 | 21 | private: 22 | const int32_t max_timeout_; 23 | std::atomic last_passed_time_; 24 | }; 25 | 26 | } // namespace Flow 27 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/flow/traffic_shaping_calculator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sentinel-core/statistic/node/node.h" 4 | 5 | namespace Sentinel { 6 | namespace Flow { 7 | 8 | class TrafficShapingCalculator { 9 | public: 10 | TrafficShapingCalculator() = default; 11 | virtual ~TrafficShapingCalculator() = default; 12 | 13 | virtual double CalculateAllowedTokens(const Stat::NodeSharedPtr& node, 14 | int acquire_count, int flag) = 0; 15 | }; 16 | 17 | } // namespace Flow 18 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/flow/traffic_shaping_checker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sentinel-core/slot/base/token_result.h" 4 | #include "sentinel-core/statistic/node/node.h" 5 | 6 | namespace Sentinel { 7 | namespace Flow { 8 | 9 | class TrafficShapingChecker { 10 | public: 11 | TrafficShapingChecker() = default; 12 | virtual ~TrafficShapingChecker() = default; 13 | 14 | virtual Slot::TokenResultSharedPtr DoCheck(const Stat::NodeSharedPtr& node, 15 | int acquire_count, 16 | double threshold) = 0; 17 | }; 18 | 19 | } // namespace Flow 20 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/flow/traffic_shaping_controller.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "sentinel-core/flow/traffic_shaping_controller.h" 4 | 5 | namespace Sentinel { 6 | namespace Flow { 7 | 8 | Slot::TokenResultSharedPtr TrafficShapingController::CanPass( 9 | const Stat::NodeSharedPtr& node, int acquire_count, int flag) { 10 | double allowed_tokens = 11 | calculator_->CalculateAllowedTokens(node, acquire_count, flag); 12 | return action_checker_->DoCheck(node, acquire_count, allowed_tokens); 13 | } 14 | 15 | } // namespace Flow 16 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/flow/traffic_shaping_controller.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/flow/traffic_shaping_calculator.h" 6 | #include "sentinel-core/flow/traffic_shaping_checker.h" 7 | #include "sentinel-core/statistic/node/node.h" 8 | 9 | namespace Sentinel { 10 | namespace Flow { 11 | 12 | class TrafficShapingController { 13 | public: 14 | TrafficShapingController( 15 | std::unique_ptr&& calculator, 16 | std::unique_ptr&& checker) 17 | : calculator_(std::move(calculator)), 18 | action_checker_(std::move(checker)) {} 19 | ~TrafficShapingController() = default; 20 | 21 | Slot::TokenResultSharedPtr CanPass(const Stat::NodeSharedPtr& node, 22 | int acquire_count, int flag); 23 | 24 | private: 25 | const std::unique_ptr calculator_; 26 | const std::unique_ptr action_checker_; 27 | }; 28 | 29 | } // namespace Flow 30 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/init/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | cc_library( 6 | name = "init_target_interface", 7 | srcs = [ 8 | "init_target.h", 9 | ], 10 | copts = DEFAULT_COPTS, 11 | ) 12 | 13 | cc_library( 14 | name = "init_target_registry_lib", 15 | srcs = [ 16 | "init_target_registry.h", 17 | ], 18 | copts = DEFAULT_COPTS, 19 | deps = [ 20 | "//sentinel-core/utils:utils_lib", 21 | ] 22 | ) 23 | 24 | cc_test( 25 | name = "init_target_registry_unittests", 26 | srcs = [ 27 | "init_target_registry_test.cc", 28 | ], 29 | copts = TEST_COPTS, 30 | deps = [ 31 | ":init_target_interface", 32 | ":init_target_registry_lib", 33 | "//sentinel-core/test/mock/init:mock_lib", 34 | "@com_google_googletest//:gtest_main", 35 | ] 36 | ) 37 | -------------------------------------------------------------------------------- /sentinel-core/init/init_target.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Sentinel { 4 | namespace Init { 5 | class Target { 6 | public: 7 | virtual ~Target() = default; 8 | virtual void Initialize() = 0; 9 | }; 10 | 11 | } // namespace Init 12 | } // namespace Sentinel 13 | -------------------------------------------------------------------------------- /sentinel-core/init/init_target_registry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sentinel-core/utils/utils.h" 4 | 5 | namespace Sentinel { 6 | namespace Init { 7 | 8 | template 9 | class InitTargetRegister { 10 | public: 11 | InitTargetRegister() { instance_.Initialize(); } 12 | 13 | T& GetInstance() { return instance_; } 14 | 15 | private: 16 | T instance_{}; 17 | }; 18 | 19 | template 20 | class InitTargetRegister> { 21 | public: 22 | InitTargetRegister(const Utils::Singleton& s) { s.get().Initialize(); } 23 | }; 24 | 25 | /** 26 | * Macro used for static registration. 27 | * Static variable initialization does not guarantee order, so each target here 28 | * cannot have mutual dependencies. 29 | */ 30 | #ifndef REGISTER_INIT_TARGET 31 | #define REGISTER_INIT_TARGET(TARGET_OBJ_TYPE) \ 32 | static Sentinel::Init::InitTargetRegister \ 33 | TARGET_OBJ_TYPE##_registered 34 | #endif 35 | #ifndef REGISTER_SINGLETON_INIT_TARGET 36 | #define REGISTER_SINGLETON_INIT_TARGET(TARGET_OBJ_TYPE, o) \ 37 | static Sentinel::Init::InitTargetRegister> \ 38 | TARGET_OBJ_TYPE##_sgt_registered(o) 39 | #endif 40 | 41 | } // namespace Init 42 | } // namespace Sentinel 43 | -------------------------------------------------------------------------------- /sentinel-core/init/init_target_registry_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "gmock/gmock.h" 4 | #include "gtest/gtest.h" 5 | 6 | #include "sentinel-core/test/mock/init/mock.h" 7 | 8 | #include "sentinel-core/init/init_target.h" 9 | #include "sentinel-core/init/init_target_registry.h" 10 | 11 | namespace Sentinel { 12 | namespace Init { 13 | 14 | TEST(InitTargetRegisterTest, TestCommonInitTargetInvoked) { 15 | REGISTER_INIT_TARGET(FakeInitTarget); 16 | EXPECT_EQ(1, FakeInitTarget_registered.GetInstance().count()); 17 | } 18 | 19 | } // namespace Init 20 | } // namespace Sentinel 21 | -------------------------------------------------------------------------------- /sentinel-core/log/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | cc_library( 6 | name = "logger_lib", 7 | srcs = [ 8 | "logger.h", 9 | "logger.cc", 10 | ], 11 | copts = DEFAULT_COPTS, 12 | deps = [ 13 | ":log_base_impl_lib", 14 | "//sentinel-core/utils:macros_lib", 15 | "@com_github_gabime_spdlog//:spdlog" 16 | ] 17 | ) 18 | 19 | 20 | cc_library( 21 | name = "log_base_interface", 22 | srcs = [ 23 | "log_base.h", 24 | ], 25 | copts = DEFAULT_COPTS, 26 | deps = [ 27 | ] 28 | ) 29 | 30 | cc_library( 31 | name = "log_base_impl_lib", 32 | srcs = [ 33 | "log_base.h", 34 | "log_base.cc", 35 | ], 36 | copts = DEFAULT_COPTS, 37 | deps = [ 38 | "@com_google_absl//absl/strings", 39 | "//sentinel-core/utils:file_utils_lib", 40 | "//sentinel-core/init:init_target_registry_lib", 41 | ] 42 | ) 43 | 44 | cc_test( 45 | name = "log_base_unittests", 46 | srcs = [ 47 | "log_base_test.cc", 48 | ], 49 | copts = TEST_COPTS, 50 | deps = [ 51 | ":log_base_impl_lib", 52 | "@com_google_googletest//:gtest_main", 53 | ] 54 | ) 55 | 56 | 57 | cc_test( 58 | name = "logger_unittests", 59 | srcs = [ 60 | "logger_unittests.cc", 61 | ], 62 | copts = TEST_COPTS, 63 | deps = [ 64 | ":logger_lib", 65 | "@com_google_absl//absl/strings:str_format", 66 | "@com_google_absl//absl/time", 67 | "@com_google_googletest//:gtest_main", 68 | ] 69 | ) -------------------------------------------------------------------------------- /sentinel-core/log/block/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | cc_library( 6 | name = "block_log_task_lib", 7 | srcs = [ 8 | "block_log_task.h", 9 | "block_log_task.cc", 10 | ], 11 | copts = DEFAULT_COPTS, 12 | deps = [ 13 | "@com_google_absl//absl/container:flat_hash_map", 14 | "@com_google_absl//absl/synchronization", 15 | "@com_google_absl//absl/strings:str_format", 16 | "@com_google_absl//absl/time", 17 | "@com_github_gabime_spdlog//:spdlog", 18 | "//sentinel-core/log:logger_lib", 19 | ] 20 | ) 21 | 22 | cc_test( 23 | name = "block_log_task_unittests", 24 | srcs = [ 25 | "block_log_task_test.cc", 26 | ], 27 | copts = TEST_COPTS, 28 | deps = [ 29 | ":block_log_task_lib", 30 | "@com_google_googletest//:gtest_main", 31 | ] 32 | ) 33 | -------------------------------------------------------------------------------- /sentinel-core/log/block/block_log_task.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "absl/container/flat_hash_map.h" 8 | #include "spdlog/spdlog.h" 9 | 10 | #include "sentinel-core/log/log_base.h" 11 | 12 | namespace Sentinel { 13 | namespace Log { 14 | 15 | static constexpr const char* kBlockLoggerName = "sentinel_block_logger"; 16 | static constexpr const char* kBlockLogFilename = "sentinel-block.log"; 17 | static constexpr uint32_t kDefaultBlockLogMaxSize = 1024 * 1024 * 300; 18 | 19 | struct BlockLogRecord { 20 | BlockLogRecord() = default; 21 | BlockLogRecord(int64_t lw, int64_t lb) : last_write_(lw), last_block_(lb) {} 22 | 23 | int64_t last_write_{0}; 24 | int64_t last_block_{0}; 25 | }; 26 | 27 | class BlockLogTask { 28 | public: 29 | BlockLogTask() : BlockLogTask(LogBase::GetLogBaseDir() + kBlockLogFilename) {} 30 | explicit BlockLogTask(const std::string& log_path); 31 | ~BlockLogTask(); 32 | 33 | void Start(); 34 | void Stop(); 35 | 36 | void Log(const std::string& resource, const std::string& cause); 37 | 38 | bool started() const { return started_.load(); } 39 | 40 | private: 41 | std::atomic_bool started_{false}; 42 | std::unique_ptr thd_; 43 | std::shared_ptr logger_; 44 | absl::flat_hash_map map_; 45 | mutable absl::Mutex mtx_; 46 | 47 | void LoopWriteBlockLog(); 48 | }; 49 | 50 | } // namespace Log 51 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/log/block/block_log_task_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "gmock/gmock.h" 8 | #include "gtest/gtest.h" 9 | 10 | #include "sentinel-core/log/block/block_log_task.h" 11 | 12 | namespace Sentinel { 13 | namespace Log { 14 | 15 | namespace { 16 | size_t GetLineNumberFromFilePath(const std::string& filename) { 17 | std::ifstream inFile(filename); 18 | return std::count(std::istreambuf_iterator(inFile), 19 | std::istreambuf_iterator(), '\n'); 20 | } 21 | } // namespace 22 | 23 | TEST(BlockLogTaskTest, TestWriteBlockLog) { 24 | std::string log_file_name = std::tmpnam(nullptr); 25 | ASSERT_TRUE(!log_file_name.empty()); 26 | BlockLogTask task(log_file_name); 27 | task.Start(); 28 | EXPECT_TRUE(task.started()); 29 | 30 | auto res1 = "some_resource"; 31 | auto res2 = "another_resource"; 32 | auto flow_exception = "FlowException"; 33 | task.Log(res1, flow_exception); 34 | task.Log(res2, flow_exception); 35 | std::this_thread::sleep_for(std::chrono::milliseconds(1100)); 36 | EXPECT_EQ(2, GetLineNumberFromFilePath(log_file_name)); 37 | 38 | task.Log(res1, flow_exception); 39 | std::this_thread::sleep_for(std::chrono::milliseconds(1100)); 40 | EXPECT_EQ(3, GetLineNumberFromFilePath(log_file_name)); 41 | } 42 | 43 | } // namespace Log 44 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/log/log_base.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/log/log_base.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "absl/strings/match.h" 7 | #include "absl/strings/string_view.h" 8 | #include "sentinel-core/utils/file_utils.h" 9 | 10 | using namespace Sentinel::Utils; 11 | 12 | namespace Sentinel { 13 | namespace Log { 14 | 15 | static constexpr auto kFileSeparator = "/"; 16 | 17 | LogBase::LogBase() { InitializeInternal(); } 18 | 19 | void LogBase::InitializeInternal() { 20 | // First use config from ENV. 21 | // If absent, then use `~/logs/csp/`. 22 | 23 | std::string str_log_dir; 24 | 25 | auto log_dir = std::getenv(kEnvLogDir); 26 | 27 | if (log_dir == nullptr) { 28 | auto home_dir = std::getenv("HOME"); 29 | if (home_dir != nullptr) { 30 | str_log_dir = std::string(home_dir); 31 | str_log_dir = AddSeparator(str_log_dir) + kDirName; 32 | } else { 33 | std::cout << "INFO: home_dir is null" << std::endl; 34 | str_log_dir = "./"; 35 | } 36 | } 37 | 38 | log_base_dir_ = AddSeparator(str_log_dir); 39 | 40 | if (!FileUtils::DirExists(str_log_dir)) { 41 | auto ret = FileUtils::CreateDir(str_log_dir); 42 | if (!ret) { 43 | // log error 44 | } 45 | } 46 | 47 | const char *use_pid = std::getenv(kEnvLogNameUsrPid); 48 | if (use_pid != nullptr && std::string(use_pid) == "true") { 49 | log_name_use_pid_ = true; 50 | } else { 51 | log_name_use_pid_ = false; 52 | } 53 | 54 | std::cout << "INFO: log base dir is: " << log_base_dir_ << std::endl; 55 | std::cout << "INFO: log name use pid is: " << log_name_use_pid_ << std::endl; 56 | } 57 | 58 | std::string LogBase::AddSeparator(const std::string &dir) { 59 | if (!absl::EndsWith(dir, kFileSeparator)) { 60 | return dir + kFileSeparator; 61 | } 62 | return dir; 63 | } 64 | 65 | } // namespace Log 66 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/log/log_base.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace Sentinel { 6 | namespace Log { 7 | 8 | static constexpr auto kEnvLogDir = "CSP_SENTINEL_LOG_DIR"; 9 | static constexpr auto kEnvLogNameUsrPid = "CSP_SENTINEL_LOG_USE_PID"; 10 | static constexpr auto kDirName = "logs/csp"; 11 | 12 | class LogBase { 13 | public: 14 | ~LogBase() = default; 15 | 16 | static LogBase& GetInstance() { 17 | static LogBase* instance = new LogBase(); 18 | return *instance; 19 | } 20 | 21 | static bool IsLogNameUsePid() { return GetInstance().log_name_use_pid_; } 22 | static std::string GetLogBaseDir() { return GetInstance().log_base_dir_; } 23 | 24 | private: 25 | LogBase(); 26 | 27 | void InitializeInternal(); 28 | static std::string AddSeparator(const std::string& dir); 29 | 30 | std::string log_base_dir_{}; 31 | bool log_name_use_pid_{false}; 32 | }; 33 | 34 | } // namespace Log 35 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/log/log_base_test.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | #define private public 4 | 5 | #include "sentinel-core/log/log_base.h" 6 | 7 | namespace Sentinel { 8 | namespace Log { 9 | 10 | TEST(LogBaseTest, TestAddSeparator) { 11 | auto ret = LogBase::AddSeparator("test_path"); 12 | EXPECT_EQ(ret, "test_path/"); 13 | 14 | ret = LogBase::AddSeparator("test_path/"); 15 | EXPECT_EQ(ret, "test_path/"); 16 | } 17 | 18 | } // namespace Log 19 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/log/logger.cc: -------------------------------------------------------------------------------- 1 | #include "logger.h" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace Sentinel { 9 | namespace Log { 10 | 11 | static constexpr const char* kDefaultRecordLogFormat = "[%H:%M:%S] [%l] %v"; 12 | 13 | const char Logger::kDefaultFileLogger[] = "default_sentinel_logger"; 14 | 15 | bool Logger::InitDefaultLogger() { 16 | return Logger::InitDefaultLogger(Logger::GetDefaultLogPath()); 17 | } 18 | 19 | bool Logger::InitDefaultLogger(const std::string& file_path) { 20 | return Logger::InitDefaultLogger(file_path, kDefaultRecordLogFormat); 21 | } 22 | 23 | bool Logger::InitDefaultLogger(const std::string& file_path, 24 | const std::string& log_format) { 25 | try { 26 | auto logger = spdlog::daily_logger_mt( 27 | kDefaultFileLogger, file_path); 28 | if (!logger) { 29 | return false; 30 | } 31 | // https://github.com/gabime/spdlog/wiki/3.-Custom-formatting 32 | if (!log_format.empty()) { 33 | logger->set_pattern(log_format); 34 | } 35 | logger->set_level(spdlog::level::info); 36 | logger->flush_on(spdlog::level::info); 37 | } catch (const spdlog::spdlog_ex& ex) { 38 | std::cerr << "Log initialization failed: " << ex.what() << std::endl; 39 | return false; 40 | } 41 | return true; 42 | } 43 | 44 | void Logger::Uninitialization() { spdlog::drop(kDefaultFileLogger); } 45 | 46 | void Logger::SetAllLoggerLevel(levels level) { 47 | spdlog::apply_all([&](std::shared_ptr l) { 48 | l->set_level(static_cast(level)); 49 | }); 50 | } 51 | 52 | void Logger::FlushAllLogger() { 53 | spdlog::apply_all([&](std::shared_ptr l) { l->flush(); }); 54 | } 55 | 56 | std::string Logger::GetDefaultLogPath() { 57 | return LogBase::GetLogBaseDir() + kRecordLogFilename; 58 | } 59 | 60 | } // namespace Log 61 | } // namespace Sentinel 62 | -------------------------------------------------------------------------------- /sentinel-core/log/metric/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | cc_library( 6 | name = "metric_log_lib", 7 | srcs = [ 8 | "metric_writer.h", 9 | "metric_writer.cc", 10 | "metric_reader.h", 11 | "metric_reader.cc", 12 | "metric_searcher.h", 13 | "metric_searcher.cc", 14 | ], 15 | copts = DEFAULT_COPTS, 16 | deps = [ 17 | "@com_google_absl//absl/strings", 18 | "@com_google_absl//absl/time", 19 | "//sentinel-core/statistic/base:metric_item_lib", 20 | "//sentinel-core/config:local_config_lib", 21 | ], 22 | ) 23 | 24 | cc_library( 25 | name = "metric_log_task_lib", 26 | srcs = [ 27 | "metric_log_task.h", 28 | "metric_log_task.cc", 29 | ], 30 | copts = DEFAULT_COPTS, 31 | deps = [ 32 | ":metric_log_lib", 33 | "//sentinel-core/init:init_target_interface", 34 | "//sentinel-core/statistic/node:resource_node_storage_lib", 35 | ] 36 | ) 37 | 38 | cc_test( 39 | name = "metric_writer_unittests", 40 | srcs = [ 41 | "metric_test_utils.h", 42 | "metric_writer_test.cc", 43 | ], 44 | copts = TEST_COPTS, 45 | deps = [ 46 | ":metric_log_lib", 47 | "@com_google_googletest//:gtest_main", 48 | ] 49 | ) 50 | 51 | cc_test( 52 | name = "metric_reader_unittests", 53 | srcs = [ 54 | "metric_test_utils.h", 55 | "metric_reader_test.cc", 56 | ], 57 | copts = TEST_COPTS, 58 | deps = [ 59 | ":metric_log_lib", 60 | "@com_google_absl//absl/time", 61 | "@com_google_googletest//:gtest_main", 62 | ], 63 | linkstatic = 1, 64 | ) 65 | 66 | cc_test( 67 | name = "metric_searcher_unittests", 68 | srcs = [ 69 | "metric_test_utils.h", 70 | "metric_searcher_test.cc", 71 | ], 72 | copts = TEST_COPTS, 73 | deps = [ 74 | ":metric_log_lib", 75 | "@com_google_googletest//:gtest_main", 76 | ], 77 | linkstatic = 1, 78 | ) 79 | 80 | -------------------------------------------------------------------------------- /sentinel-core/log/metric/metric_log_task.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "sentinel-core/init/init_target.h" 10 | #include "sentinel-core/log/metric/metric_writer.h" 11 | #include "sentinel-core/statistic/base/metric_item.h" 12 | 13 | namespace Sentinel { 14 | namespace Log { 15 | 16 | using MetricItemTimeMap = 17 | std::map>; 18 | 19 | class MetricLogTask : public Init::Target { 20 | public: 21 | MetricLogTask(); 22 | virtual ~MetricLogTask(); 23 | void Initialize() override; 24 | 25 | void Stop(); 26 | 27 | private: 28 | std::unique_ptr writer_; 29 | std::atomic stopped_{false}; 30 | std::unique_ptr thd_; 31 | 32 | void RunLogTask(); 33 | void AggregateMetrics( 34 | MetricItemTimeMap& map, 35 | std::unordered_map&& metrics, 36 | const std::string& resource); 37 | }; 38 | 39 | } // namespace Log 40 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/log/metric/metric_reader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "sentinel-core/statistic/base/metric_item.h" 7 | 8 | namespace Sentinel { 9 | namespace Log { 10 | 11 | class MetricReader { 12 | public: 13 | std::vector ReadMetrics( 14 | const std::vector &file_names, int pos, int64_t offset, 15 | int recommend_lines_); 16 | void ReadMetricsInOneFile(std::vector &metric_vec, 17 | const std::string &file_name, int64_t offset, 18 | int recommend_lines); 19 | 20 | std::vector ReadMetricsByEndTime( 21 | const std::vector file_names, int pos, int64_t offset, 22 | int64_t begin_time_ms, int64_t end_time_ms, const std::string &identity); 23 | bool ReadMetricsInOneFileByEndTime( 24 | std::vector &metric_vec, 25 | const std::string &file_name, int64_t offset, int64_t begin_time_ms, 26 | int64_t end_time_ms, const std::string &identity); 27 | 28 | private: 29 | static const int kMaxLinesReturn = 100000; 30 | }; 31 | 32 | } // namespace Log 33 | } // namespace Sentinel 34 | -------------------------------------------------------------------------------- /sentinel-core/log/metric/metric_searcher.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "sentinel-core/log/metric/metric_reader.h" 8 | #include "sentinel-core/statistic/base/metric_item.h" 9 | 10 | namespace Sentinel { 11 | namespace Log { 12 | 13 | struct Position { 14 | std::string metric_file_name = ""; 15 | std::string index_file_name = ""; 16 | int64_t offset_in_index = -1; 17 | int64_t second = -1; 18 | }; 19 | 20 | class MetricSearcher { 21 | public: 22 | MetricSearcher(const std::string &base_dir, 23 | const std::string &base_file_name); 24 | std::vector Find(int64_t begin_time_ms, 25 | int recommend_lines); 26 | std::vector FindByTimeAndResource( 27 | int64_t begin_time_ms, int64_t end_time_ms, const std::string &identity); 28 | 29 | private: 30 | bool ValidPosition(int64_t begin_time_ms); 31 | int64_t FindOffset(int64_t begin_time, const std::string &metric_file_name, 32 | const std::string &idx_file_name, int64_t offset_in_index); 33 | 34 | private: 35 | std::string base_dir_; 36 | std::string base_file_name_; 37 | Position last_pos_; 38 | 39 | MetricReader metric_reader_; 40 | 41 | std::mutex lock_; 42 | }; 43 | 44 | } // namespace Log 45 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/log/metric/metric_test_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "sentinel-core/config/local_config.h" 10 | #include "sentinel-core/log/log_base.h" 11 | #include "sentinel-core/log/metric/metric_writer.h" 12 | #include "sentinel-core/utils/file_utils.h" 13 | 14 | namespace Sentinel { 15 | namespace Log { 16 | namespace MetricTestUtils { 17 | constexpr int64_t kSingleFileSize = 10000; 18 | constexpr int64_t kTotalFileCount = 10000; 19 | 20 | void TestWriteMetricLog(int64_t time) { 21 | MetricWriter writer(kSingleFileSize, kTotalFileCount); 22 | 23 | std::vector nodes; 24 | Stat::MetricItemSharedPtr node = std::make_shared(); 25 | node->set_timestamp(123456); 26 | node->set_pass_qps(123); 27 | node->set_block_qps(456); 28 | node->set_complete_qps(789); 29 | node->set_exception_qps(13323); 30 | node->set_rt(11); 31 | node->set_resource("resource_context"); 32 | nodes.push_back(node); 33 | 34 | writer.Write(time, nodes); 35 | writer.Write(time + 1000, nodes); 36 | writer.Close(); 37 | } 38 | 39 | std::string GetAppName() { 40 | auto app_name = Config::LocalConfig::GetInstance().app_name(); 41 | return app_name; 42 | } 43 | 44 | void RemoveTestLogFile() { 45 | auto files = Utils::FileUtils::ListFiles(LogBase::GetLogBaseDir()); 46 | for (auto &file_name : files) { 47 | auto path = LogBase::GetLogBaseDir() + file_name; 48 | remove(path.c_str()); 49 | } 50 | } 51 | 52 | } // namespace MetricTestUtils 53 | } // namespace Log 54 | } // namespace Sentinel 55 | -------------------------------------------------------------------------------- /sentinel-core/param/param_flow_item.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/param/param_flow_item.h" 2 | #include "absl/strings/str_format.h" 3 | 4 | namespace Sentinel { 5 | namespace Param { 6 | 7 | bool ParamFlowItem::operator==(const ParamFlowItem& item) const noexcept { 8 | return param_type_ == item.param_type_ && param_value_ == item.param_value_ && 9 | threshold_ == item.threshold_; 10 | } 11 | 12 | std::string ParamFlowItem::ToString() const { 13 | std::string typeName; 14 | if (IsInt32(param_value_)) { 15 | typeName = "int32_t"; 16 | } else if (IsInt64(param_value_)) { 17 | typeName = "int64_t"; 18 | } else if (IsString(param_value_)) { 19 | typeName = "String"; 20 | } else { 21 | typeName = "unknown"; 22 | } 23 | return absl::StrFormat("ParamFlowItem{threshold=%.2lf, type=%s}", threshold_, 24 | typeName); 25 | } 26 | 27 | ParamFlowItemList::ParamFlowItemList( 28 | std::initializer_list args) { 29 | for (const auto& arg : args) { 30 | this->push_back(arg); 31 | } 32 | } 33 | 34 | bool ParamFlowItemList::operator==(const ParamFlowItemList& list) const 35 | noexcept { 36 | if (this->size() != list.size()) { 37 | return false; 38 | } 39 | for (int i = 0; i < this->size(); i++) { 40 | if (!(list[i] == this->at(i))) { 41 | return false; 42 | } 43 | } 44 | return true; 45 | } 46 | 47 | std::string ParamFlowItemList::ToString() const { 48 | std::string str("["); 49 | for (const auto& item : *this) { 50 | str += item.ToString(); 51 | str += ","; 52 | } 53 | str += "]"; 54 | return str; 55 | } 56 | 57 | } // namespace Param 58 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/param/param_flow_item.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "absl/types/any.h" 7 | #include "sentinel-core/param/param_flow_rule_constants.h" 8 | #include "sentinel-core/param/statistic/any_cmp.h" 9 | 10 | namespace Sentinel { 11 | namespace Param { 12 | 13 | class ParamFlowItem { 14 | public: 15 | ParamFlowItem() : threshold_(-1) {} 16 | ParamFlowItem(absl::any param_value, ParamItemType param_type, 17 | double threshold = -1) 18 | : param_value_(param_value), 19 | threshold_(threshold), 20 | param_type_(param_type) {} 21 | 22 | ParamItemType param_type() const { return param_type_; } 23 | absl::any param_value() const { return param_value_; } 24 | double threshold() const { return threshold_; } 25 | 26 | void set_param_type(ParamItemType param_type) { param_type_ = param_type; } 27 | void set_param_value(absl::any param_value) { param_value_ = param_value; } 28 | void set_threshold(double threshold) { threshold_ = threshold; } 29 | bool operator==(const ParamFlowItem& item) const noexcept; 30 | std::string ToString() const; 31 | 32 | private: 33 | ParamItemType param_type_; 34 | absl::any param_value_; 35 | double threshold_ = -1; 36 | }; 37 | 38 | class ParamFlowItemList : public std::vector { 39 | public: 40 | ParamFlowItemList() = default; 41 | ParamFlowItemList(std::initializer_list args); 42 | bool operator==(const ParamFlowItemList& list) const noexcept; 43 | std::string ToString() const; 44 | }; 45 | 46 | } // namespace Param 47 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/param/param_flow_rule.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/param/param_flow_rule.h" 2 | #include "absl/strings/str_format.h" 3 | 4 | namespace Sentinel { 5 | namespace Param { 6 | 7 | void ParamFlowRule::FillExceptionFlowItems() const { 8 | if (specific_item_list_.size() == 0) { 9 | return; 10 | } 11 | for (auto& item : specific_item_list_) { 12 | parsed_hot_items_->insert( 13 | std::make_pair<>(item.param_value(), item.threshold())); 14 | } 15 | } 16 | 17 | bool ParamFlowRule::operator==(const ParamFlowRule& rule) const { 18 | if (!(resource_ == rule.resource() && param_idx_ == rule.param_idx() && 19 | metric_type_ == rule.metric_type() && threshold_ == rule.threshold() && 20 | interval_in_ms_ == rule.interval_in_ms() && 21 | sample_count_ == rule.sample_count() && 22 | cache_size_ == rule.cache_size() && 23 | cluster_mode_ == rule.cluster_mode() && 24 | specific_item_list_.size() == rule.specific_item_list_.size())) { 25 | return false; 26 | } 27 | for (int i = 0; i < specific_item_list_.size(); i++) { 28 | if (!(rule.specific_item_list_[i] == specific_item_list_[i])) { 29 | return false; 30 | } 31 | } 32 | return true; 33 | } 34 | 35 | std::string ParamFlowRule::ToString() const { 36 | return absl::StrFormat( 37 | "ParamFlowRule{resource=%s, param_idx=%d, metric_type=%d, " 38 | "threshold=%.2f, interval_in_ms=%d, sample_count=%d, " 39 | "cache_size=%d, cluster_mode=%d, specific_item_list=%s}", 40 | resource_, param_idx_, static_cast(metric_type_), threshold_, 41 | interval_in_ms_, sample_count_, cache_size_, cluster_mode_, 42 | specific_item_list_.ToString()); 43 | } 44 | 45 | } // namespace Param 46 | } // namespace Sentinel 47 | -------------------------------------------------------------------------------- /sentinel-core/param/param_flow_rule_checker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "sentinel-core/common/entry.h" 3 | #include "sentinel-core/param/param_flow_rule.h" 4 | #include "sentinel-core/param/statistic/param_metric.h" 5 | #include "sentinel-core/slot/base/token_result.h" 6 | 7 | namespace Sentinel { 8 | namespace Param { 9 | 10 | class ParamFlowChecker { 11 | public: 12 | ParamFlowChecker() = default; 13 | ~ParamFlowChecker() = default; 14 | 15 | static bool PassCheck(ParamMetricSharedPtr& metric, 16 | const ParamFlowRuleSharedPtr& rule, int count, 17 | const std::vector& params); 18 | 19 | private: 20 | static bool PassLocalCheck(ParamMetricSharedPtr& metric, 21 | const ParamFlowRuleSharedPtr& rule, int count, 22 | const std::vector& params); 23 | static bool PassSingleValueCheck(ParamMetricSharedPtr& metric, 24 | const ParamFlowRuleSharedPtr& rule, 25 | int count, const absl::any& param); 26 | }; 27 | 28 | } // namespace Param 29 | } // namespace Sentinel 30 | -------------------------------------------------------------------------------- /sentinel-core/param/param_flow_rule_constants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Sentinel { 4 | namespace Param { 5 | 6 | enum class ParamFlowMetricType { 7 | kThreadCount = 0, 8 | kQps = 1, // default mode 9 | kNum 10 | }; 11 | 12 | enum class ParamFlowRelationStrategy { 13 | kDirect = 0, // default relation strategy 14 | kAssociatedResource = 1, 15 | kInvocationChainEntrance = 2 16 | }; 17 | 18 | enum class ParamFlowControlBehavior { 19 | kReject = 0, // default behavior 20 | kWarmUp = 1, 21 | kThrotting = 2, 22 | kWarmUpThrottling = 3 23 | }; 24 | 25 | enum class ParamItemType { 26 | kString = 0, // Default type 27 | kInt32 = 1, 28 | kInt64 = 2, 29 | 30 | kNum 31 | }; 32 | 33 | static constexpr const char* kString = "String"; 34 | static constexpr const char* kInt32 = "int"; 35 | static constexpr const char* kInt64 = "long"; 36 | 37 | } // namespace Param 38 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/param/param_flow_slot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sentinel-core/param/param_flow_rule_checker.h" 4 | #include "sentinel-core/param/param_flow_rule_manager.h" 5 | #include "sentinel-core/slot/base/rule_checker_slot.h" 6 | 7 | namespace Sentinel { 8 | namespace Slot { 9 | 10 | constexpr auto kParamFlowSlotName = "ParamFlowSlot"; 11 | using MetricMap = 12 | tbb::concurrent_hash_map; 13 | using MetricMapSharedPtr = std::shared_ptr; 14 | 15 | class ParamFlowSlot : public RuleCheckerSlot { 16 | public: 17 | ParamFlowSlot() = default; 18 | virtual ~ParamFlowSlot() = default; 19 | 20 | TokenResultSharedPtr Entry(const EntrySharedPtr& entry, Stat::NodeSharedPtr&, 21 | int count, int flag, 22 | const std::vector& params) override; 23 | void Exit(const EntrySharedPtr& entry, int count, 24 | const std::vector& params) override; 25 | const std::string& Name() const override; 26 | void initHotParamMetricsFor(const std::string& resource, 27 | const Param::ParamFlowRuleSharedPtr& rule); 28 | TokenResultSharedPtr CheckFlow(const std::string& resource, int count, 29 | const std::vector& params); 30 | 31 | friend class Param::ParamFlowRuleManager; 32 | 33 | static Param::ParamMetricSharedPtr GetParamMetric( 34 | const std::string& resource); 35 | 36 | private: 37 | static MetricMapSharedPtr metric_map_; 38 | const std::string name_{kParamFlowSlotName}; 39 | Param::ParamFlowChecker checker_{}; 40 | }; 41 | 42 | } // namespace Slot 43 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/param/statistic/any_cmp.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/param/statistic/any_cmp.h" 2 | #include "sentinel-core/log/logger.h" 3 | 4 | namespace Sentinel { 5 | namespace Param { 6 | 7 | const std::string INT_TYPE_STR(typeid(3).name()); 8 | const std::string INT32_TYPE_STR(typeid(static_cast(3)).name()); 9 | const std::string INT64_TYPE_STR(typeid(static_cast(3L)).name()); 10 | const std::string STRING_TYPE_STR(typeid(std::string("example_str")).name()); 11 | 12 | bool IsInt32(const absl::any& a) { 13 | return INT_TYPE_STR.compare(a.type().name()) == 0; 14 | } 15 | bool IsInt64(const absl::any& a) { 16 | return INT64_TYPE_STR.compare(a.type().name()) == 0; 17 | } 18 | bool IsString(const absl::any& a) { 19 | std::string type_str(a.type().name()); 20 | return type_str.find(STRING_TYPE_STR) != type_str.npos; 21 | } 22 | 23 | } // namespace Param 24 | } // namespace Sentinel 25 | 26 | namespace absl { 27 | using Sentinel::Param::IsInt32; 28 | using Sentinel::Param::IsInt64; 29 | using Sentinel::Param::IsString; 30 | 31 | bool operator==(const absl::any& any1, const absl::any& any2) { 32 | if (IsInt32(any1) && IsInt32(any2)) { 33 | return absl::any_cast(any1) == absl::any_cast(any2); 34 | } else if (IsInt64(any1) && IsInt64(any2)) { 35 | return absl::any_cast(any1) == absl::any_cast(any2); 36 | } else if (IsString(any1) && IsString(any2)) { 37 | return absl::any_cast(any1).compare( 38 | absl::any_cast(any2)) == 0; 39 | } 40 | return false; 41 | } 42 | 43 | } // namespace absl -------------------------------------------------------------------------------- /sentinel-core/param/statistic/any_cmp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "absl/types/any.h" 5 | 6 | namespace Sentinel { 7 | namespace Param { 8 | 9 | extern const std::string INT_TYPE_STR; 10 | extern const std::string INT64_TYPE_STR; 11 | extern const std::string STRING_TYPE_STR; 12 | 13 | bool IsInt32(const absl::any& a); 14 | bool IsInt64(const absl::any& a); 15 | bool IsString(const absl::any& a); 16 | 17 | } // namespace Param 18 | } // namespace Sentinel 19 | 20 | namespace std { 21 | 22 | using Sentinel::Param::IsInt32; 23 | using Sentinel::Param::IsInt64; 24 | using Sentinel::Param::IsString; 25 | 26 | template <> 27 | struct hash { 28 | size_t operator()(const absl::any& any) const { 29 | if (IsInt32(any)) { 30 | return 31 * absl::any_cast(any); 31 | } else if (IsInt64(any)) { 32 | return 31 * absl::any_cast(any); 33 | } else if (IsString(any)) { 34 | return std::hash{}(absl::any_cast(any)); 35 | } 36 | return -1; 37 | } 38 | }; 39 | 40 | } // namespace std 41 | 42 | namespace absl { 43 | using Sentinel::Param::IsInt32; 44 | using Sentinel::Param::IsInt64; 45 | using Sentinel::Param::IsString; 46 | bool operator==(const absl::any& any1, const absl::any& any2); 47 | } // namespace absl 48 | 49 | namespace Sentinel { 50 | namespace Param { 51 | 52 | struct AnyCmp { 53 | static size_t hash(const absl::any& a) { return std::hash{}(a); } 54 | static bool equal(const absl::any& a0, const absl::any& a1) { 55 | return a0 == a1; 56 | } 57 | }; 58 | 59 | } // namespace Param 60 | } // namespace Sentinel 61 | -------------------------------------------------------------------------------- /sentinel-core/param/statistic/any_cmp_test.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/param/statistic/any_cmp.h" 2 | #include 3 | 4 | int main() { 5 | absl::any a; 6 | std::cout << a.has_value(); 7 | 8 | std::cout << a.type().name() << std::endl; 9 | const std::string INT_TYPE_STR(typeid(3).name()); 10 | 11 | return 0; 12 | } -------------------------------------------------------------------------------- /sentinel-core/param/statistic/param_bucket.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/param/statistic/param_bucket.h" 2 | 3 | namespace Sentinel { 4 | namespace Param { 5 | 6 | ParamBucket::ParamBucket(int capacity) { 7 | for (int i = 0; i < static_cast(ParamMetricEvent::Count); i++) { 8 | counters_.push_back(std::make_unique(capacity)); 9 | } 10 | } 11 | 12 | int ParamBucket::Get(const ParamMetricEvent& e, const absl::any& value) const { 13 | int i = static_cast(e); 14 | ScalableCache::HashMapConstAccessor cac; 15 | if (counters_[i]->find(cac, value)) { 16 | return cac->second.m_value->load(); 17 | } else { 18 | return 0; 19 | } 20 | } 21 | 22 | void ParamBucket::Add(const ParamMetricEvent& e, int count, 23 | const absl::any& value) { 24 | int i = static_cast(e); 25 | counters_[i]->increase(value, count); // Create a new pair if not present 26 | } 27 | 28 | void ParamBucket::Reset() { 29 | for (int i = 0; i < static_cast(ParamMetricEvent::Count); i++) { 30 | counters_[i]->clear(); 31 | } 32 | } 33 | 34 | void ParamBucket::GetPairSet(const ParamMetricEvent& e, 35 | HotPairList& pairs) const { 36 | int i = static_cast(e); 37 | counters_[i]->snapshotPairs(pairs); 38 | } 39 | 40 | } // namespace Param 41 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/param/statistic/param_bucket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "absl/types/any.h" 9 | #include "any_cmp.h" 10 | #include "sentinel-core/param/statistic/param_event.h" 11 | #include "sentinel-core/param/statistic/scalable_cache.h" 12 | 13 | namespace Sentinel { 14 | namespace Param { 15 | 16 | using ScalableCache = ThreadSafeScalableCache; 17 | using ScalableCacheUniquePtr = std::unique_ptr; 18 | using HotPair = std::pair; 19 | using HotPairList = std::vector; 20 | 21 | class ParamBucket { 22 | public: 23 | ParamBucket(int capacity); 24 | 25 | int Get(const ParamMetricEvent& e, const absl::any& value) const; 26 | void Add(const ParamMetricEvent& e, int count, const absl::any& value); 27 | void Reset(); 28 | void GetPairSet(const ParamMetricEvent& e, HotPairList& pairs) const; 29 | 30 | private: 31 | std::vector counters_; 32 | }; 33 | 34 | } // namespace Param 35 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/param/statistic/param_event.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Sentinel { 4 | namespace Param { 5 | 6 | enum class ParamMetricEvent { 7 | PASS = 0, 8 | BLOCK, 9 | 10 | Count, // hack for getting length of enum 11 | }; 12 | 13 | } // namespace Param 14 | } // namespace Sentinel 15 | -------------------------------------------------------------------------------- /sentinel-core/param/statistic/param_leap_array.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/param/statistic/param_leap_array.h" 2 | 3 | namespace Sentinel { 4 | namespace Param { 5 | 6 | int ParamLeapArray::cache_size() const noexcept { return cache_size_; } 7 | void ParamLeapArray::set_cache_size(int cache_size) noexcept { 8 | cache_size_ = cache_size; 9 | } 10 | 11 | ParamLeapArray::ParamLeapArray(int32_t sample_count, int32_t interval_ms, 12 | int32_t cache_size) 13 | : cache_size_(cache_size), 14 | Stat::LeapArray(sample_count, interval_ms) {} 15 | 16 | std::shared_ptr ParamLeapArray::NewEmptyBucket( 17 | int64_t time_millis) { 18 | return std::make_shared(cache_size_); 19 | } 20 | 21 | void ParamLeapArray::ResetWindowTo( 22 | const Stat::WindowWrapSharedPtr& wrap, int64_t start_time) { 23 | wrap->ResetTo(start_time); 24 | wrap->Value()->Reset(); 25 | } 26 | 27 | HotPairList&& ParamLeapArray::GetTopValues(const ParamMetricEvent& e, 28 | int number) { 29 | this->CurrentWindow(); 30 | auto v = this->Values(); 31 | HotPairList pairs; 32 | for (const auto& bucket : v) { 33 | bucket->GetPairSet(e, pairs); 34 | } 35 | std::sort(pairs.begin(), pairs.end(), 36 | [](const HotPair& p0, const HotPair& p1) -> bool { 37 | return p0.second < p1.second; 38 | }); 39 | 40 | int size = number < pairs.size() ? number : pairs.size(); 41 | return HotPairList(pairs.begin(), pairs.begin() + size); 42 | } 43 | 44 | HotPairList&& ParamLeapArray::GetTopPassValues(int number) { 45 | return GetTopValues(ParamMetricEvent::PASS, number); 46 | } 47 | 48 | } // namespace Param 49 | } // namespace Sentinel 50 | -------------------------------------------------------------------------------- /sentinel-core/param/statistic/param_leap_array.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "sentinel-core/param/statistic/param_bucket.h" 4 | #include "sentinel-core/statistic/base/leap_array.h" 5 | 6 | namespace Sentinel { 7 | namespace Param { 8 | 9 | class ParamLeapArray : public Stat::LeapArray { 10 | public: 11 | ParamLeapArray(int32_t sample_count, int32_t interval_ms, 12 | int32_t cache_size = DEFAULT_CACHE_SIZE); 13 | std::shared_ptr NewEmptyBucket(int64_t time_millis); 14 | void ResetWindowTo(const Stat::WindowWrapSharedPtr& wrap, 15 | int64_t start_time); 16 | 17 | int cache_size() const noexcept; 18 | void set_cache_size(int cache_size) noexcept; 19 | 20 | HotPairList&& GetTopValues(const ParamMetricEvent& e, int number); 21 | HotPairList&& GetTopPassValues(int number); 22 | 23 | private: 24 | int cache_size_; 25 | const static int DEFAULT_CACHE_SIZE = 200; 26 | }; 27 | 28 | using ParamLeapArraySharedPtr = std::shared_ptr; 29 | 30 | } // namespace Param 31 | } // namespace Sentinel 32 | -------------------------------------------------------------------------------- /sentinel-core/param/statistic/param_leap_array_key.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace Sentinel { 5 | namespace Param { 6 | 7 | class ParamLeapArrayKey { 8 | public: 9 | int32_t param_idx_ = -1; 10 | int32_t interval_in_ms_ = 1000; 11 | int32_t sample_count_ = 1; 12 | int32_t cache_size_; 13 | int32_t param_idx() const noexcept { return param_idx_; } 14 | int32_t interval_in_ms() const noexcept { return interval_in_ms_; } 15 | int32_t sample_count() const noexcept { return sample_count_; } 16 | int32_t cache_size() const noexcept { return cache_size_; } 17 | }; 18 | using ParamLeapArrayKeySharedPtr = std::shared_ptr; 19 | 20 | class ParamLeapArrayKeyPtrHashEq { 21 | public: 22 | static size_t hash(const ParamLeapArrayKeySharedPtr& key) { 23 | if (!key) { 24 | return 0; 25 | } 26 | size_t result = key->interval_in_ms_; 27 | result = 31 * result + key->sample_count_; 28 | result = 31 * result + key->param_idx_; 29 | result = 31 * result + key->cache_size_; 30 | return result; 31 | } 32 | static bool equal(const ParamLeapArrayKeySharedPtr& k0, 33 | const ParamLeapArrayKeySharedPtr& k1) { 34 | if (!k0 && !k1) { 35 | return true; 36 | } else if (!k0 || !k1) { 37 | return false; 38 | } 39 | return k0->interval_in_ms_ == k1->interval_in_ms_ && 40 | k0->sample_count_ == k1->sample_count_ && 41 | k0->param_idx_ == k1->param_idx_ && 42 | k0->cache_size_ == k1->cache_size_; 43 | } 44 | }; 45 | 46 | } // namespace Param 47 | } // namespace Sentinel 48 | -------------------------------------------------------------------------------- /sentinel-core/property/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | cc_library( 6 | name = "property_listener_interface", 7 | srcs = [ 8 | "property_listener.h", 9 | ], 10 | copts = DEFAULT_COPTS, 11 | deps = [] 12 | ) 13 | 14 | cc_library( 15 | name = "sentinel_property_interface", 16 | srcs = [ 17 | "sentinel_property.h", 18 | ], 19 | copts = DEFAULT_COPTS, 20 | deps = [ 21 | ":property_listener_interface", 22 | "//sentinel-core/log:logger_lib", 23 | ] 24 | ) 25 | 26 | cc_library( 27 | name = "dynamic_sentinel_property_lib", 28 | srcs = [ 29 | "dynamic_sentinel_property.h", 30 | ], 31 | copts = DEFAULT_COPTS, 32 | deps = [ 33 | ":sentinel_property_interface", 34 | "@com_google_absl//absl/container:flat_hash_map", 35 | ] 36 | ) 37 | 38 | cc_test( 39 | name = "dynamic_sentinel_property_unittests", 40 | srcs = [ 41 | "dynamic_sentinel_property_unittests.cc", 42 | ], 43 | copts = TEST_COPTS, 44 | deps = [ 45 | ":dynamic_sentinel_property_lib", 46 | "//sentinel-core/test/mock/property:mock_lib", 47 | "//sentinel-core/test/mock/common:mock_lib", 48 | "@com_google_googletest//:gtest_main", 49 | ] 50 | ) 51 | -------------------------------------------------------------------------------- /sentinel-core/property/dynamic_sentinel_property.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "sentinel-core/log/logger.h" 8 | #include "sentinel-core/property/sentinel_property.h" 9 | 10 | namespace Sentinel { 11 | namespace Property { 12 | 13 | template 14 | class DynamicSentinelProperty : public SentinelProperty { 15 | public: 16 | DynamicSentinelProperty() = default; 17 | virtual ~DynamicSentinelProperty() = default; 18 | void AddListener(PropertyListenerPtr&& listener) override { 19 | auto name = listener->Name(); 20 | listeners_.emplace(std::make_pair(std::string(name), std::move(listener))); 21 | } 22 | 23 | void RemoveListener(const std::string& listener_name) override { 24 | listeners_.erase(listener_name); 25 | } 26 | 27 | bool UpdateValue(const T& value) override { 28 | if (last_value_ == value) { 29 | return false; 30 | } 31 | 32 | last_value_ = value; 33 | SENTINEL_LOG(info, "starting to config update"); 34 | for (auto it = listeners_.begin(); it != listeners_.end(); ++it) { 35 | it->second->ConfigUpdate(value, false); 36 | } 37 | 38 | return true; 39 | } 40 | 41 | void Clear() { listeners_.clear(); } 42 | 43 | private: 44 | T last_value_; 45 | std::unordered_map> listeners_; 46 | }; 47 | } // namespace Property 48 | } // namespace Sentinel 49 | -------------------------------------------------------------------------------- /sentinel-core/property/dynamic_sentinel_property_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "gmock/gmock.h" 4 | #include "gtest/gtest.h" 5 | 6 | #include "sentinel-core/property/dynamic_sentinel_property.h" 7 | #include "sentinel-core/test/mock/common/mock.h" 8 | #include "sentinel-core/test/mock/property/mock.h" 9 | 10 | using testing::_; 11 | using testing::InSequence; 12 | using testing::Matcher; 13 | using testing::Return; 14 | using testing::ReturnRef; 15 | 16 | namespace Sentinel { 17 | namespace Property { 18 | 19 | TEST(DynamicSentinelPropertyTest, Basic) { 20 | FakeRule rule; 21 | rule.set_fake_rule_data("test"); 22 | DynamicSentinelProperty ds; 23 | auto pl = std::make_unique>(); 24 | auto pl_point = pl.get(); 25 | 26 | EXPECT_CALL(*pl_point, ConfigUpdate(Matcher(rule), false)) 27 | .Times(1); 28 | 29 | ds.AddListener(std::move(pl)); 30 | ds.UpdateValue(rule); 31 | } 32 | 33 | } // namespace Property 34 | } // namespace Sentinel 35 | -------------------------------------------------------------------------------- /sentinel-core/property/property_listener.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace Sentinel { 7 | namespace Property { 8 | 9 | template 10 | class PropertyListener { 11 | public: 12 | virtual ~PropertyListener() = default; 13 | 14 | virtual void ConfigUpdate(const T& value, bool first_load) = 0; 15 | virtual const std::string Name() const = 0; 16 | }; 17 | 18 | template 19 | using PropertyListenerPtr = std::unique_ptr>; 20 | 21 | } // namespace Property 22 | } // namespace Sentinel 23 | -------------------------------------------------------------------------------- /sentinel-core/property/sentinel_property.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "sentinel-core/property/property_listener.h" 7 | 8 | namespace Sentinel { 9 | namespace Property { 10 | 11 | template 12 | class SentinelProperty { 13 | public: 14 | virtual ~SentinelProperty() = default; 15 | virtual void AddListener(PropertyListenerPtr&& listener) = 0; 16 | virtual void RemoveListener(const std::string& listener_name) = 0; 17 | virtual bool UpdateValue(const T& value) = 0; 18 | }; 19 | 20 | template 21 | using SentinelPropertySharedPtr = std::shared_ptr>; 22 | 23 | } // namespace Property 24 | } // namespace Sentinel 25 | -------------------------------------------------------------------------------- /sentinel-core/public/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | cc_library( 6 | name = "sph_u_lib", 7 | srcs = [ 8 | "sph_u.h", 9 | # "sph_u.cc", 10 | ], 11 | copts = DEFAULT_COPTS, 12 | deps = [ 13 | "//sentinel-core/common:global_status", 14 | "//sentinel-core/common:entry_result_lib", 15 | "//sentinel-core/common:string_resource_wrapper_lib", 16 | ] 17 | ) 18 | 19 | cc_test( 20 | name = "sph_u_unittests", 21 | srcs = [ 22 | "sph_u_test.cc", 23 | ], 24 | copts = TEST_COPTS, 25 | deps = [ 26 | ":sph_u_lib", 27 | "//sentinel-core/log:logger_lib", 28 | "//sentinel-core/flow:flow_rule_manager_lib", 29 | "//sentinel-core/statistic/node:resource_node_storage_lib", 30 | "@com_google_googletest//:gtest_main", 31 | ] 32 | ) -------------------------------------------------------------------------------- /sentinel-core/public/sph_u_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "gmock/gmock.h" 5 | #include "gtest/gtest.h" 6 | 7 | #include "sentinel-core/flow/flow_rule_manager.h" 8 | #include "sentinel-core/public/sph_u.h" 9 | #include "sentinel-core/statistic/node/resource_node_storage.h" 10 | 11 | namespace Sentinel { 12 | 13 | TEST(SphUTest, TestEntryBlockSimple) { 14 | auto resource_name = "SphUTest::TestEntryBlockSimple"; 15 | 16 | Flow::FlowRule rule{resource_name}; 17 | rule.set_count(0); 18 | Flow::FlowRuleManager& m = Flow::FlowRuleManager::GetInstance(); 19 | m.LoadRules({rule}); 20 | 21 | auto r = SphU::Entry(resource_name); 22 | 23 | EXPECT_TRUE(r->IsBlocked()); 24 | auto entry = r->entry(); 25 | EXPECT_TRUE(entry == nullptr); 26 | 27 | auto& s = Stat::ResourceNodeStorage::GetInstance(); 28 | auto node = s.GetClusterNode(resource_name); 29 | EXPECT_FALSE(node == nullptr); 30 | EXPECT_DOUBLE_EQ(0, node->PassQps()); 31 | EXPECT_DOUBLE_EQ(1, node->BlockQps()); 32 | EXPECT_EQ(0, node->CurThreadNum()); 33 | EXPECT_DOUBLE_EQ(0, node->CompleteQps()); 34 | } 35 | 36 | TEST(SphUTest, TestEntryPassWithoutRules) { 37 | Flow::FlowRuleManager& m = Flow::FlowRuleManager::GetInstance(); 38 | m.LoadRules({}); 39 | 40 | auto resource_name = "SphUTest::TestEntryPassWithoutRules"; 41 | auto r = SphU::Entry(resource_name); 42 | EXPECT_FALSE(r->IsBlocked()); 43 | auto entry = r->entry(); 44 | EXPECT_FALSE(entry == nullptr); 45 | EXPECT_FALSE(entry->exited()); 46 | 47 | auto& s = Stat::ResourceNodeStorage::GetInstance(); 48 | auto node = s.GetClusterNode(resource_name); 49 | EXPECT_FALSE(node == nullptr); 50 | EXPECT_DOUBLE_EQ(1, node->PassQps()); 51 | EXPECT_DOUBLE_EQ(0, node->BlockQps()); 52 | EXPECT_EQ(1, node->CurThreadNum()); 53 | EXPECT_DOUBLE_EQ(0, node->CompleteQps()); 54 | 55 | r->Exit(); 56 | EXPECT_TRUE(entry->exited()); 57 | 58 | EXPECT_DOUBLE_EQ(1, node->PassQps()); 59 | EXPECT_DOUBLE_EQ(0, node->BlockQps()); 60 | EXPECT_EQ(0, node->CurThreadNum()); 61 | EXPECT_DOUBLE_EQ(1, node->CompleteQps()); 62 | } 63 | 64 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/slot/base/default_slot_chain_impl.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/slot/base/default_slot_chain_impl.h" 2 | 3 | #include 4 | 5 | namespace Sentinel { 6 | namespace Slot { 7 | 8 | void DefaultSlotChainImpl::AddFirst(std::unique_ptr&& slot) { 9 | // The StatsSlot type slot is forbidden to be placed in the first position 10 | assert(slot->Type() != SlotType::STATS_SLOT); 11 | slots_.emplace_front(std::move(slot)); 12 | } 13 | void DefaultSlotChainImpl::AddLast(std::unique_ptr&& slot) { 14 | slots_.emplace_back(std::move(slot)); 15 | } 16 | 17 | TokenResultSharedPtr DefaultSlotChainImpl::Entry( 18 | const EntrySharedPtr& entry, Stat::NodeSharedPtr& node, int count, int flag, 19 | const std::vector& params) { 20 | auto context = entry != nullptr ? entry->context() : nullptr; 21 | auto token_result = TokenResult::Ok(); 22 | for (auto elem = slots_.begin(); elem != slots_.end(); ++elem) { 23 | if ((*elem)->IsContinue(token_result, context)) { 24 | token_result = (*elem)->Entry(entry, node, count, flag, params); 25 | } 26 | } 27 | return token_result; 28 | } 29 | 30 | void DefaultSlotChainImpl::Exit(const EntrySharedPtr& entry, int count, 31 | const std::vector& params) { 32 | for (auto elem = slots_.begin(); elem != slots_.end(); ++elem) { 33 | (*elem)->Exit(entry, count, params); 34 | } 35 | } 36 | 37 | } // namespace Slot 38 | } // namespace Sentinel 39 | -------------------------------------------------------------------------------- /sentinel-core/slot/base/default_slot_chain_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "sentinel-core/slot/base/slot_chain.h" 8 | #include "sentinel-core/slot/base/token_result.h" 9 | 10 | namespace Sentinel { 11 | namespace Slot { 12 | 13 | class DefaultSlotChainImpl : public SlotChain { 14 | public: 15 | DefaultSlotChainImpl() = default; 16 | virtual ~DefaultSlotChainImpl() = default; 17 | 18 | // SlotChain 19 | void AddFirst(std::unique_ptr&& slot) override; 20 | void AddLast(std::unique_ptr&& slot) override; 21 | TokenResultSharedPtr Entry(const EntrySharedPtr& entry, 22 | Stat::NodeSharedPtr& node, int count, int flag, 23 | const std::vector& params) override; 24 | void Exit(const EntrySharedPtr& entry, int count, 25 | const std::vector& params) override; 26 | 27 | private: 28 | std::deque> slots_; 29 | }; 30 | 31 | } // namespace Slot 32 | } // namespace Sentinel 33 | -------------------------------------------------------------------------------- /sentinel-core/slot/base/rule_checker_slot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/slot/base/slot.h" 6 | 7 | namespace Sentinel { 8 | namespace Slot { 9 | 10 | class RuleCheckerSlot : public Slot { 11 | public: 12 | virtual ~RuleCheckerSlot() = default; 13 | bool IsContinue(const TokenResultSharedPtr& token, 14 | const EntryContextSharedPtr&) override { 15 | if (token->status() != TokenStatus::RESULT_STATUS_OK) { 16 | return false; 17 | } 18 | return true; 19 | } 20 | 21 | SlotType Type() const override { 22 | static constexpr SlotType type = SlotType::RULE_CHECKER_SLOT; 23 | return type; 24 | } 25 | }; 26 | 27 | } // namespace Slot 28 | } // namespace Sentinel 29 | -------------------------------------------------------------------------------- /sentinel-core/slot/base/slot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sentinel-core/slot/base/slot_base.h" 4 | 5 | namespace Sentinel { 6 | namespace Slot { 7 | 8 | enum class SlotType { 9 | RULE_CHECKER_SLOT, 10 | STATS_SLOT, 11 | STATS_PREPARE_SLOT, 12 | }; 13 | 14 | class Slot : public SlotBase { 15 | public: 16 | virtual ~Slot() = default; 17 | virtual bool IsContinue(const TokenResultSharedPtr& token, 18 | const EntryContextSharedPtr& context) = 0; 19 | virtual const std::string& Name() const = 0; 20 | virtual SlotType Type() const = 0; 21 | }; 22 | 23 | } // namespace Slot 24 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/slot/base/slot_base.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "sentinel-core/common/entry.h" 7 | #include "sentinel-core/common/resource_wrapper.h" 8 | #include "sentinel-core/slot/base/slot_base.h" 9 | #include "sentinel-core/slot/base/token_result.h" 10 | 11 | namespace Sentinel { 12 | namespace Slot { 13 | 14 | class SlotBase { 15 | public: 16 | virtual ~SlotBase() = default; 17 | virtual TokenResultSharedPtr Entry(const EntrySharedPtr& entry, 18 | Stat::NodeSharedPtr& node, int count, 19 | int flag, 20 | const std::vector& params) = 0; 21 | virtual void Exit(const EntrySharedPtr& entry, int count, 22 | const std::vector& params) = 0; 23 | }; 24 | 25 | } // namespace Slot 26 | } // namespace Sentinel 27 | -------------------------------------------------------------------------------- /sentinel-core/slot/base/slot_chain.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/slot/base/slot.h" 6 | 7 | namespace Sentinel { 8 | namespace Slot { 9 | 10 | class SlotChain : public SlotBase { 11 | public: 12 | virtual ~SlotChain() = default; 13 | virtual void AddFirst(std::unique_ptr&& slot) = 0; 14 | virtual void AddLast(std::unique_ptr&& slot) = 0; 15 | }; 16 | 17 | using SlotChainSharedPtr = std::shared_ptr; 18 | 19 | } // namespace Slot 20 | } // namespace Sentinel 21 | -------------------------------------------------------------------------------- /sentinel-core/slot/base/stats_slot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "sentinel-core/slot/base/slot.h" 7 | 8 | namespace Sentinel { 9 | namespace Slot { 10 | 11 | class StatsSlot : public Slot { 12 | public: 13 | virtual ~StatsSlot() = default; 14 | 15 | /* 16 | * Statistics class slot default always continue the rest of the slot 17 | * TODO(tianqian.zyf): TokenResultSharedPtr should be passed over the entire 18 | * slot chain using the SlotChainContext method. 19 | */ 20 | bool IsContinue(const TokenResultSharedPtr& token, 21 | const EntryContextSharedPtr& context) override { 22 | assert(context != nullptr); 23 | // We need to check nullptr to prevent unexpected circumstances. 24 | if (context != nullptr) { 25 | context->set_last_token_result(token); 26 | } 27 | return true; 28 | } 29 | 30 | SlotType Type() const override { 31 | static constexpr SlotType type = SlotType::STATS_SLOT; 32 | return type; 33 | } 34 | }; 35 | 36 | } // namespace Slot 37 | } // namespace Sentinel 38 | -------------------------------------------------------------------------------- /sentinel-core/slot/base/token_result.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "sentinel-core/slot/base/token_result.h" 3 | 4 | namespace Sentinel { 5 | namespace Slot { 6 | 7 | TokenResultSharedPtr TokenResult::cachedOkPtr = 8 | std::make_shared(TokenStatus::RESULT_STATUS_OK); 9 | 10 | TokenResultSharedPtr TokenResult::Ok() { return cachedOkPtr; } 11 | 12 | TokenResultSharedPtr TokenResult::Blocked(const std::string& blocked_reason) { 13 | return std::make_shared(TokenStatus::RESULT_STATUS_BLOCKED, 14 | blocked_reason); 15 | } 16 | 17 | TokenResultSharedPtr TokenResult::ShouldWait( 18 | std::chrono::milliseconds wait_ms) { 19 | return std::make_shared(TokenStatus::RESULT_STATUS_SHOULD_WAIT, 20 | wait_ms); 21 | } 22 | 23 | } // namespace Slot 24 | } // namespace Sentinel 25 | -------------------------------------------------------------------------------- /sentinel-core/slot/base/token_result.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "absl/types/optional.h" 7 | 8 | namespace Sentinel { 9 | namespace Slot { 10 | enum class TokenStatus { 11 | RESULT_STATUS_OK = 0, 12 | RESULT_STATUS_BLOCKED = 1, 13 | RESULT_STATUS_SHOULD_WAIT = 2, 14 | }; 15 | 16 | class TokenResult; 17 | 18 | using TokenResultSharedPtr = std::shared_ptr; 19 | class TokenResult { 20 | public: 21 | TokenResult(TokenStatus status) : status_(status) {} 22 | TokenResult(TokenStatus status, const std::string& blocked_reason) 23 | : status_(status), blocked_reason_(blocked_reason) {} 24 | TokenResult(TokenStatus status, std::chrono::milliseconds wait_ms) 25 | : status_(status), wait_ms_(wait_ms) {} 26 | 27 | static TokenResultSharedPtr Ok(); 28 | static TokenResultSharedPtr Blocked(const std::string& blocked_reason); 29 | static TokenResultSharedPtr ShouldWait(std::chrono::milliseconds wait_ms); 30 | TokenStatus status() const { return status_; } 31 | absl::optional blocked_reason() const { 32 | return blocked_reason_; 33 | }; 34 | absl::optional wait_ms() const { 35 | return wait_ms_; 36 | }; 37 | 38 | private: 39 | const TokenStatus status_; 40 | static TokenResultSharedPtr cachedOkPtr; 41 | absl::optional blocked_reason_; 42 | absl::optional wait_ms_; 43 | }; 44 | 45 | } // namespace Slot 46 | } // namespace Sentinel 47 | -------------------------------------------------------------------------------- /sentinel-core/slot/global_slot_chain.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "sentinel-core/circuitbreaker/slot.h" 4 | #include "sentinel-core/flow/flow_slot.h" 5 | #include "sentinel-core/param/param_flow_slot.h" 6 | #include "sentinel-core/slot/base/default_slot_chain_impl.h" 7 | #include "sentinel-core/slot/base/slot_chain.h" 8 | #include "sentinel-core/slot/log_slot.h" 9 | #include "sentinel-core/slot/resource_node_builder_slot.h" 10 | #include "sentinel-core/slot/statistic_slot.h" 11 | #include "sentinel-core/system/system_slot.h" 12 | 13 | namespace Sentinel { 14 | namespace Slot { 15 | 16 | namespace { 17 | SlotChainSharedPtr BuildDefaultSlotChain() { 18 | auto chain = std::make_shared(); 19 | chain->AddLast(std::make_unique()); 20 | 21 | chain->AddLast(std::make_unique()); 22 | chain->AddLast(std::make_unique()); 23 | chain->AddLast(std::make_unique()); 24 | chain->AddLast(std::make_unique()); 25 | 26 | chain->AddLast(std::make_unique()); 27 | chain->AddLast(std::make_unique()); 28 | chain->AddLast(std::make_unique()); 29 | return chain; 30 | } // namespace 31 | } // namespace 32 | 33 | SlotChainSharedPtr GetGlobalSlotChain() { 34 | static SlotChainSharedPtr GlobalSlotChain = BuildDefaultSlotChain(); 35 | return GlobalSlotChain; 36 | } 37 | 38 | } // namespace Slot 39 | } // namespace Sentinel 40 | -------------------------------------------------------------------------------- /sentinel-core/slot/global_slot_chain.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/slot/base/slot_chain.h" 6 | 7 | namespace Sentinel { 8 | namespace Slot { 9 | 10 | SlotChainSharedPtr GetGlobalSlotChain(); 11 | 12 | } // namespace Slot 13 | } // namespace Sentinel 14 | -------------------------------------------------------------------------------- /sentinel-core/slot/log_slot.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/slot/log_slot.h" 2 | 3 | #include "sentinel-core/log/log_base.h" 4 | #include "sentinel-core/utils/time_utils.h" 5 | 6 | using namespace Sentinel::Utils; 7 | 8 | namespace Sentinel { 9 | namespace Slot { 10 | 11 | LogSlot::LogSlot() { 12 | log_task_ = std::make_unique(); 13 | log_task_->Start(); 14 | } 15 | 16 | TokenResultSharedPtr LogSlot::Entry(const EntrySharedPtr& entry, 17 | /*const*/ Stat::NodeSharedPtr& node, 18 | int count, int flag, 19 | const std::vector& params) { 20 | if (entry == nullptr || entry->context() == nullptr) { 21 | return TokenResult::Ok(); 22 | } 23 | TokenResultSharedPtr prev_result = entry->context()->last_token_result(); 24 | if (prev_result == nullptr) { 25 | return TokenResult::Ok(); 26 | } 27 | if (prev_result->status() == TokenStatus::RESULT_STATUS_BLOCKED) { 28 | log_task_->Log(entry->resource()->name(), 29 | prev_result->blocked_reason().value_or("unknown")); 30 | } 31 | return prev_result; 32 | } 33 | 34 | void LogSlot::Exit(const EntrySharedPtr&, int, 35 | const std::vector& params) { 36 | // Do nothing 37 | } 38 | 39 | } // namespace Slot 40 | } // namespace Sentinel 41 | -------------------------------------------------------------------------------- /sentinel-core/slot/log_slot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/log/block/block_log_task.h" 6 | #include "sentinel-core/log/log_base.h" 7 | #include "sentinel-core/slot/base/stats_slot.h" 8 | #include "sentinel-core/slot/log_slot.h" 9 | #include "sentinel-core/utils/time_utils.h" 10 | 11 | using namespace Sentinel::Utils; 12 | 13 | namespace Sentinel { 14 | namespace Slot { 15 | 16 | constexpr auto kLogSlotName = "LogSlot"; 17 | 18 | class LogSlot : public StatsSlot { 19 | public: 20 | LogSlot(); 21 | virtual ~LogSlot() = default; 22 | 23 | const std::string& Name() const override { return name_; }; 24 | TokenResultSharedPtr Entry(const EntrySharedPtr& entry, 25 | /*const*/ Stat::NodeSharedPtr& node, int count, 26 | int flag, 27 | const std::vector& params) override; 28 | void Exit(const EntrySharedPtr& entry, int count, 29 | const std::vector& params) override; 30 | 31 | private: 32 | const std::string name_{kLogSlotName}; 33 | 34 | std::unique_ptr log_task_; 35 | }; 36 | 37 | } // namespace Slot 38 | } // namespace Sentinel 39 | -------------------------------------------------------------------------------- /sentinel-core/slot/resource_node_builder_slot.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "sentinel-core/slot/resource_node_builder_slot.h" 5 | 6 | namespace Sentinel { 7 | namespace Slot { 8 | 9 | const std::string& ResourceNodeBuilderSlot::Name() const { return name_; } 10 | 11 | TokenResultSharedPtr ResourceNodeBuilderSlot::Entry( 12 | const EntrySharedPtr& entry, Stat::NodeSharedPtr& node, int, int, 13 | const std::vector& params) { 14 | auto cluster_node = 15 | node_storage_.GetOrCreateClusterNode(entry->resource()->name()); 16 | entry->set_cur_node(cluster_node); 17 | 18 | if (cluster_node && !entry->context()->tag().empty()) { 19 | Stat::NodeSharedPtr tag_node = 20 | cluster_node->GetOrCreateTagNode(entry->context()->tag()); 21 | entry->context()->set_tag_node(tag_node); 22 | } 23 | 24 | node = cluster_node; 25 | 26 | return TokenResult::Ok(); 27 | } 28 | 29 | void ResourceNodeBuilderSlot::Exit(const EntrySharedPtr&, int, 30 | const std::vector& params) { 31 | // Do nothing. 32 | } 33 | 34 | } // namespace Slot 35 | } // namespace Sentinel 36 | -------------------------------------------------------------------------------- /sentinel-core/slot/resource_node_builder_slot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "sentinel-core/slot/base/stats_slot.h" 7 | #include "sentinel-core/statistic/node/resource_node_storage.h" 8 | 9 | namespace Sentinel { 10 | namespace Slot { 11 | 12 | constexpr auto kResourceNodeBuilderSlotName = "ResourceNodeBuilderSlot"; 13 | 14 | class ResourceNodeBuilderSlot : public StatsSlot { 15 | public: 16 | ResourceNodeBuilderSlot() = default; 17 | virtual ~ResourceNodeBuilderSlot() = default; 18 | 19 | TokenResultSharedPtr Entry(const EntrySharedPtr& entry, 20 | Stat::NodeSharedPtr& node, int count, int flag, 21 | const std::vector& params) override; 22 | void Exit(const EntrySharedPtr& entry, int count, 23 | const std::vector& params) override; 24 | const std::string& Name() const override; 25 | 26 | private: 27 | const std::string name_{kResourceNodeBuilderSlotName}; 28 | 29 | Stat::ResourceNodeStorage& node_storage_ = 30 | Stat::ResourceNodeStorage::GetInstance(); 31 | }; 32 | 33 | } // namespace Slot 34 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/statistic/base/bucket_leap_array.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/statistic/base/bucket_leap_array.h" 2 | 3 | namespace Sentinel { 4 | namespace Stat { 5 | 6 | std::shared_ptr BucketLeapArray::NewEmptyBucket(int64_t) { 7 | return std::make_shared(); 8 | } 9 | 10 | void BucketLeapArray::ResetWindowTo(const WindowWrapSharedPtr& w, 11 | int64_t start_time) { 12 | // Update the start time and reset value. 13 | w->ResetTo(start_time); 14 | w->Value()->Reset(); 15 | } 16 | 17 | } // namespace Stat 18 | } // namespace Sentinel 19 | -------------------------------------------------------------------------------- /sentinel-core/statistic/base/bucket_leap_array.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/statistic/base/leap_array.h" 6 | #include "sentinel-core/statistic/base/metric_bucket.h" 7 | 8 | namespace Sentinel { 9 | namespace Stat { 10 | 11 | class BucketLeapArray : public LeapArray { 12 | public: 13 | explicit BucketLeapArray(int32_t sample_count, int32_t interval_ms) 14 | : LeapArray(sample_count, interval_ms) {} 15 | virtual ~BucketLeapArray() {} 16 | 17 | std::shared_ptr NewEmptyBucket(int64_t time_millis) override; 18 | void ResetWindowTo(const WindowWrapSharedPtr& wrap, 19 | int64_t start_time) override; 20 | }; 21 | 22 | } // namespace Stat 23 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/statistic/base/metric_bucket.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "sentinel-core/statistic/base/metric_bucket.h" 4 | 5 | namespace Sentinel { 6 | namespace Stat { 7 | 8 | MetricBucket& MetricBucket::Reset() { 9 | int size = (int)MetricEvent::Count; 10 | for (int i = 0; i < size; i++) { 11 | counters_[i].store(0); 12 | } 13 | InitMinRt(); 14 | return *this; 15 | } 16 | 17 | int64_t MetricBucket::Get(const MetricEvent& event) const { 18 | int i = (int)event; 19 | return counters_[i].load(); 20 | } 21 | 22 | int64_t MetricBucket::MinRt() const { return min_rt_; } 23 | 24 | void MetricBucket::Add(const MetricEvent& event, int64_t n) { 25 | int i = (int)event; 26 | counters_[i].fetch_add(n); 27 | } 28 | 29 | void MetricBucket::AddRt(int64_t rt) { 30 | Add(MetricEvent::RT, rt); 31 | // Not thread-safe, but it's okay. 32 | if (rt < min_rt_) { 33 | min_rt_ = rt; 34 | } 35 | } 36 | 37 | void MetricBucket::InitMinRt() { min_rt_ = Constants::kMaxAllowedRt; } 38 | 39 | } // namespace Stat 40 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/statistic/base/metric_bucket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "sentinel-core/common/constants.h" 7 | #include "sentinel-core/statistic/base/metric_event.h" 8 | 9 | namespace Sentinel { 10 | namespace Stat { 11 | class MetricBucket { 12 | public: 13 | explicit MetricBucket() { InitMinRt(); } 14 | ~MetricBucket() = default; 15 | 16 | MetricBucket& Reset(); 17 | int64_t Get(const MetricEvent& event) const; 18 | int64_t MinRt() const; 19 | void Add(const MetricEvent& event, int64_t n); 20 | void AddRt(int64_t rt); 21 | 22 | private: 23 | const std::unique_ptr[]> counters_ = 24 | std::make_unique[]>( 25 | static_cast(MetricEvent::Count)); 26 | long min_rt_; 27 | 28 | void InitMinRt(); 29 | }; 30 | 31 | } // namespace Stat 32 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/statistic/base/metric_event.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Sentinel { 4 | namespace Stat { 5 | 6 | enum class MetricEvent { 7 | PASS, 8 | BLOCK, 9 | EXCEPTION, 10 | COMPLETE, 11 | RT, 12 | 13 | Count, // hack for getting length of enum 14 | }; 15 | 16 | } // namespace Stat 17 | } // namespace Sentinel 18 | -------------------------------------------------------------------------------- /sentinel-core/statistic/base/metric_item.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace Sentinel { 7 | namespace Stat { 8 | 9 | class MetricItem; 10 | 11 | using MetricItemSharedPtr = std::shared_ptr; 12 | 13 | class MetricItem { 14 | public: 15 | MetricItem() = default; 16 | 17 | static MetricItemSharedPtr FromThinString(const std::string& thin_str); 18 | static MetricItemSharedPtr FromFatString(const std::string& fat_str); 19 | 20 | const std::string& resource() const { return resource_; }; 21 | int64_t timestamp() const { return timestamp_; }; 22 | int64_t pass_qps() const { return pass_qps_; }; 23 | int64_t block_qps() const { return block_qps_; }; 24 | int64_t complete_qps() const { return complete_qps_; }; 25 | int64_t exception_qps() const { return exception_qps_; }; 26 | int64_t rt() const { return rt_; }; 27 | 28 | void set_resource(const std::string& resource) { resource_ = resource; }; 29 | void set_timestamp(int64_t t) { timestamp_ = t; }; 30 | void set_pass_qps(int64_t p) { pass_qps_ = p; }; 31 | void set_block_qps(int64_t b) { block_qps_ = b; }; 32 | void set_complete_qps(int64_t c) { complete_qps_ = c; }; 33 | void set_exception_qps(int64_t e) { exception_qps_ = e; }; 34 | void set_rt(int64_t rt) { rt_ = rt; }; 35 | 36 | std::string ToThinString() const; 37 | std::string ToFatString() const; 38 | 39 | private: 40 | std::string resource_; 41 | int64_t timestamp_; 42 | int64_t pass_qps_; 43 | int64_t block_qps_; 44 | int64_t complete_qps_; 45 | int64_t exception_qps_; 46 | int64_t rt_; 47 | }; // MetricNode in Java version 48 | 49 | } // namespace Stat 50 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/statistic/base/metric_item_test.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | #include "sentinel-core/statistic/base/metric_item.h" 4 | 5 | namespace Sentinel { 6 | namespace Stat { 7 | 8 | TEST(MetricItemTest, TestToThinString) { 9 | MetricItem item; 10 | item.set_resource("MetricItemTest|TestToThinString"); 11 | item.set_timestamp(1529998904000); 12 | item.set_pass_qps(10); 13 | item.set_block_qps(1); 14 | item.set_complete_qps(10); 15 | item.set_exception_qps(0); 16 | item.set_rt(3); 17 | 18 | auto str = "1529998904000|MetricItemTest_TestToThinString|10|1|10|0|3"; 19 | EXPECT_EQ(str, item.ToThinString()); 20 | } 21 | 22 | TEST(MetricItemTest, TestFromThinString) { 23 | auto str = "1529998908000|MetricItemTest::TestFromThinString|10|1|10|0|3"; 24 | MetricItemSharedPtr item = MetricItem::FromThinString(str); 25 | EXPECT_TRUE(item != nullptr); 26 | EXPECT_EQ(item->resource(), "MetricItemTest::TestFromThinString"); 27 | EXPECT_EQ(item->timestamp(), 1529998908000); 28 | EXPECT_EQ(item->pass_qps(), 10); 29 | EXPECT_EQ(item->block_qps(), 1); 30 | EXPECT_EQ(item->complete_qps(), 10); 31 | EXPECT_EQ(item->exception_qps(), 0); 32 | EXPECT_EQ(item->rt(), 3); 33 | } 34 | 35 | TEST(MetricItemTest, TestFromFatString) { 36 | auto str = 37 | "1529998913000|2018-06-26 " 38 | "15:41:53|MetricItemTest::TestFromFatString|10|1|10|2|25"; 39 | MetricItemSharedPtr item = MetricItem::FromFatString(str); 40 | EXPECT_TRUE(item != nullptr); 41 | EXPECT_EQ(item->resource(), "MetricItemTest::TestFromFatString"); 42 | EXPECT_EQ(item->timestamp(), 1529998913000); 43 | EXPECT_EQ(item->pass_qps(), 10); 44 | EXPECT_EQ(item->block_qps(), 1); 45 | EXPECT_EQ(item->complete_qps(), 10); 46 | EXPECT_EQ(item->exception_qps(), 2); 47 | EXPECT_EQ(item->rt(), 25); 48 | } 49 | 50 | } // namespace Stat 51 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/statistic/base/sliding_window_metric.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/statistic/base/bucket_leap_array.h" 6 | #include "sentinel-core/statistic/base/metric.h" 7 | #include "sentinel-core/statistic/base/metric_bucket.h" 8 | #include "sentinel-core/statistic/base/metric_event.h" 9 | 10 | namespace Sentinel { 11 | namespace Stat { 12 | 13 | class SlidingWindowMetric : public Metric { 14 | public: 15 | explicit SlidingWindowMetric(int32_t sample_count, int32_t interval_ms) 16 | : sliding_window_( 17 | std::make_unique(sample_count, interval_ms)) {} 18 | virtual ~SlidingWindowMetric() = default; 19 | 20 | long GetSum(const MetricEvent& event); 21 | double GetAvg(const MetricEvent& event); 22 | 23 | long Complete() override; 24 | long MaxComplete() override; 25 | long Exception() override; 26 | long Block() override; 27 | long Pass() override; 28 | long Rt() override; 29 | long MinRt() override; 30 | 31 | void AddException(int n) override; 32 | void AddBlock(int n) override; 33 | void AddComplete(int n) override; 34 | void AddPass(int n) override; 35 | void AddRt(long rt) override; 36 | 37 | std::vector Details() override; 38 | 39 | double WindowIntervalInSec() const override; 40 | int SampleCount() const override; 41 | 42 | private: 43 | const std::unique_ptr> sliding_window_; 44 | }; 45 | 46 | } // namespace Stat 47 | } // namespace Sentinel 48 | -------------------------------------------------------------------------------- /sentinel-core/statistic/base/sliding_window_metric_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "gmock/gmock.h" 4 | #include "gtest/gtest.h" 5 | 6 | #include "sentinel-core/statistic/base/sliding_window_metric.h" 7 | 8 | using testing::_; 9 | using testing::InSequence; 10 | using testing::Return; 11 | 12 | namespace Sentinel { 13 | namespace Stat { 14 | 15 | TEST(SlidingWindowMetricTest, TestOperateMetric) { 16 | auto metric = std::make_shared(2, 1000); 17 | metric->AddBlock(3); 18 | metric->AddBlock(1); 19 | metric->AddPass(2); 20 | 21 | EXPECT_EQ(4, metric->Block()); 22 | EXPECT_EQ(2, metric->Pass()); 23 | } 24 | 25 | } // namespace Stat 26 | } // namespace Sentinel 27 | -------------------------------------------------------------------------------- /sentinel-core/statistic/base/stat_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/common/constants.h" 6 | 7 | namespace Sentinel { 8 | namespace Stat { 9 | 10 | class StatConfig { 11 | public: 12 | static StatConfig& GetInstance() { 13 | static StatConfig* instance = new StatConfig(); 14 | return *instance; 15 | } 16 | 17 | friend class StatConfigManager; 18 | 19 | int32_t SampleCount() const { return sample_count_; }; 20 | int32_t IntervalMs() const { return interval_ms_; }; 21 | 22 | private: 23 | int32_t sample_count_ = Constants::kDefaultSampleCount; 24 | int32_t interval_ms_ = Constants::kDefaultIntervalMs; 25 | 26 | StatConfig() = default; 27 | }; 28 | 29 | } // namespace Stat 30 | } // namespace Sentinel 31 | -------------------------------------------------------------------------------- /sentinel-core/statistic/base/stat_config_manager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/property/sentinel_property.h" 6 | #include "sentinel-core/statistic/base/stat_config.h" 7 | 8 | namespace Sentinel { 9 | namespace Stat { 10 | 11 | class StatConfigManager { 12 | public: 13 | static StatConfigManager& GetInstance() { 14 | static StatConfigManager* instance = new StatConfigManager(); 15 | return *instance; 16 | } 17 | 18 | void UpdateSampleCount(int32_t new_sample_count); 19 | void UpdateInterval(int32_t new_interval_ms); 20 | 21 | void RegisterSampleCountProperty( 22 | const Property::SentinelPropertySharedPtr& property); 23 | void RegisterIntervalProperty( 24 | const Property::SentinelPropertySharedPtr& property); 25 | 26 | private: 27 | StatConfigManager() = default; 28 | }; 29 | 30 | class SampleCountPropertyListener : public Property::PropertyListener { 31 | public: 32 | SampleCountPropertyListener() = default; 33 | ~SampleCountPropertyListener() = default; 34 | 35 | void ConfigUpdate(const int32_t& value, bool first_load) override; 36 | const std::string Name() const override { 37 | return "SampleCountPropertyListener"; 38 | } 39 | }; 40 | 41 | class IntervalPropertyListener : public Property::PropertyListener { 42 | public: 43 | IntervalPropertyListener() = default; 44 | ~IntervalPropertyListener() = default; 45 | 46 | void ConfigUpdate(const int32_t& value, bool first_load) override; 47 | const std::string Name() const override { 48 | return "IntervalPropertyListener"; 49 | }; 50 | }; 51 | 52 | } // namespace Stat 53 | } // namespace Sentinel 54 | -------------------------------------------------------------------------------- /sentinel-core/statistic/base/window_wrap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace Sentinel { 6 | namespace Stat { 7 | 8 | template 9 | class WindowWrap { 10 | public: 11 | explicit WindowWrap(int64_t length_ms, int64_t start, 12 | const std::shared_ptr& value) 13 | : bucket_start_(start), bucket_length_ms_(length_ms), value_(value) {} 14 | ~WindowWrap() = default; 15 | 16 | int64_t BucketLengthInMs() const; 17 | int64_t BucketStart() const; 18 | std::shared_ptr Value() const; 19 | 20 | void ResetTo(int64_t start_time); 21 | bool IsTimeInBucket(int64_t time_millis) const; 22 | 23 | private: 24 | int64_t bucket_start_; 25 | const int64_t bucket_length_ms_; 26 | const std::shared_ptr value_; 27 | }; 28 | 29 | template 30 | using WindowWrapSharedPtr = std::shared_ptr>; 31 | 32 | template 33 | int64_t WindowWrap::BucketLengthInMs() const { 34 | return bucket_length_ms_; 35 | } 36 | 37 | template 38 | int64_t WindowWrap::BucketStart() const { 39 | return bucket_start_; 40 | } 41 | 42 | template 43 | std::shared_ptr WindowWrap::Value() const { 44 | return value_; 45 | } 46 | 47 | template 48 | void WindowWrap::ResetTo(int64_t start_time) { 49 | this->bucket_start_ = start_time; 50 | } 51 | 52 | template 53 | bool WindowWrap::IsTimeInBucket(int64_t time_millis) const { 54 | return bucket_start_ <= time_millis && 55 | time_millis < bucket_start_ + bucket_length_ms_; 56 | } 57 | 58 | } // namespace Stat 59 | } // namespace Sentinel 60 | -------------------------------------------------------------------------------- /sentinel-core/statistic/node/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | cc_library( 6 | name = "node_interface", 7 | srcs = [ 8 | "node.h", 9 | ], 10 | copts = DEFAULT_COPTS, 11 | deps = [ 12 | "//sentinel-core/statistic/base:metric_item_lib", 13 | ] 14 | ) 15 | 16 | cc_library( 17 | name = "statistic_node_lib", 18 | srcs = [ 19 | "statistic_node.h", 20 | "statistic_node.cc", 21 | ], 22 | copts = DEFAULT_COPTS, 23 | deps = [ 24 | ":node_interface", 25 | "//sentinel-core/statistic/base:sliding_window_metric_lib", 26 | "//sentinel-core/statistic/base:stat_config_lib", 27 | ] 28 | ) 29 | 30 | cc_library( 31 | name = "cluster_node_lib", 32 | srcs = [ 33 | "cluster_node.h", 34 | "cluster_node.cc", 35 | ], 36 | copts = DEFAULT_COPTS, 37 | deps = [ 38 | ":statistic_node_lib", 39 | "@com_google_absl//absl/container:flat_hash_map", 40 | ] 41 | ) 42 | 43 | cc_library( 44 | name = "resource_node_storage_lib", 45 | srcs = [ 46 | "resource_node_storage.h", 47 | "resource_node_storage.cc", 48 | ], 49 | copts = DEFAULT_COPTS, 50 | deps = [ 51 | "//sentinel-core/statistic/node:cluster_node_lib", 52 | "@com_google_absl//absl/container:flat_hash_map", 53 | "@com_google_absl//absl/synchronization", 54 | ] 55 | ) -------------------------------------------------------------------------------- /sentinel-core/statistic/node/cluster_node.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/statistic/node/cluster_node.h" 2 | 3 | namespace Sentinel { 4 | namespace Stat { 5 | 6 | StatisticNodeSharedPtr ClusterNode::GetTagNode(const std::string& tag) const { 7 | absl::ReaderMutexLock lck(&node_map_mtx_); 8 | auto got = tag_node_map_.find(tag); 9 | if (got == tag_node_map_.end()) { 10 | return nullptr; 11 | } 12 | return got->second; 13 | } 14 | 15 | StatisticNodeSharedPtr ClusterNode::GetOrCreateTagNode(const std::string& tag) { 16 | auto tag_node = GetTagNode(tag); 17 | if (tag_node == nullptr) { 18 | absl::WriterMutexLock lck(&node_map_mtx_); 19 | if (tag_node_map_.size() > Constants::kMaxTagSize) { 20 | SENTINEL_LOG(warn, "Tag node size exceeds the threshold {}", 21 | Constants::kMaxTagSize); 22 | return nullptr; 23 | } else { 24 | // The node is absent, create a new node for the classification_id. 25 | tag_node = std::make_shared(); 26 | tag_node_map_.insert(std::make_pair(tag, tag_node)); 27 | } 28 | } 29 | 30 | return tag_node; 31 | } 32 | 33 | void ClusterNode::TraceException(int count) { 34 | if (count > 0) { 35 | this->AddExceptionRequest(count); 36 | } 37 | } 38 | 39 | } // namespace Stat 40 | } // namespace Sentinel 41 | -------------------------------------------------------------------------------- /sentinel-core/statistic/node/cluster_node.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "sentinel-core/statistic/node/statistic_node.h" 8 | 9 | #include "absl/container/flat_hash_map.h" 10 | 11 | namespace Sentinel { 12 | namespace Stat { 13 | 14 | class ClusterNode : public StatisticNode { 15 | public: 16 | explicit ClusterNode() = default; 17 | virtual ~ClusterNode() {} 18 | 19 | StatisticNodeSharedPtr GetTagNode(const std::string& tag) const; 20 | StatisticNodeSharedPtr GetOrCreateTagNode(const std::string& tag); 21 | void TraceException(int32_t count); 22 | 23 | public: 24 | absl::flat_hash_map tag_node_map_; 25 | mutable absl::Mutex node_map_mtx_; 26 | }; 27 | 28 | using ClusterNodeSharedPtr = std::shared_ptr; 29 | 30 | } // namespace Stat 31 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/statistic/node/node.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "sentinel-core/statistic/base/metric_item.h" 7 | 8 | namespace Sentinel { 9 | namespace Stat { 10 | 11 | class Node { 12 | public: 13 | virtual ~Node() = default; 14 | 15 | virtual int64_t TotalCountInMinute() = 0; 16 | virtual int64_t PassCountInMinute() = 0; 17 | virtual int64_t CompleteCountInMinute() = 0; 18 | virtual int64_t BlockCountInMinute() = 0; 19 | virtual int64_t ExceptionCountInMinute() = 0; 20 | 21 | virtual double PassQps() = 0; 22 | virtual double BlockQps() = 0; 23 | virtual double TotalQps() = 0; 24 | virtual double CompleteQps() = 0; 25 | virtual double MaxCompleteQps() = 0; 26 | virtual double ExceptionQps() = 0; 27 | 28 | virtual double AvgRt() = 0; 29 | virtual double MinRt() = 0; 30 | virtual uint32_t CurThreadNum() const = 0; 31 | 32 | virtual double PreviousBlockQps() = 0; 33 | virtual double PreviousPassQps() = 0; 34 | 35 | virtual std::unordered_map Metrics() = 0; 36 | 37 | virtual void AddPassRequest(int32_t count) = 0; 38 | virtual void AddRtAndCompleteRequest(int32_t rt, int32_t completeCount) = 0; 39 | virtual void AddBlockRequest(int32_t count) = 0; 40 | virtual void AddExceptionRequest(int32_t count) = 0; 41 | virtual void IncreaseThreadNum() = 0; 42 | virtual void DecreaseThreadNum() = 0; 43 | 44 | virtual void Reset() = 0; 45 | }; 46 | 47 | using NodeSharedPtr = std::shared_ptr; 48 | 49 | } // namespace Stat 50 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/statistic/node/resource_node_storage.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "sentinel-core/common/constants.h" 5 | #include "sentinel-core/log/logger.h" 6 | #include "sentinel-core/statistic/node/resource_node_storage.h" 7 | 8 | namespace Sentinel { 9 | namespace Stat { 10 | 11 | Stat::ClusterNodeSharedPtr ResourceNodeStorage::GetClusterNode( 12 | const std::string& resource_name) const { 13 | absl::ReaderMutexLock lck(&node_map_mtx_); 14 | auto got = node_map_.find(resource_name); 15 | if (got == node_map_.end()) { 16 | return nullptr; 17 | } 18 | return got->second; 19 | } 20 | 21 | Stat::ClusterNodeSharedPtr ResourceNodeStorage::GetOrCreateClusterNode( 22 | const std::string& resource_name) { 23 | auto cluster_node = GetClusterNode(resource_name); 24 | if (cluster_node == nullptr) { 25 | absl::WriterMutexLock lck(&node_map_mtx_); 26 | auto got = node_map_.find(resource_name); 27 | if (got == node_map_.end()) { 28 | if (node_map_.size() >= Constants::kMaxResourceSize) { 29 | SENTINEL_LOG(warn, "Resource node size exceeds the threshold {}", 30 | Constants::kMaxResourceSize); 31 | } 32 | // Resource node not found, so we create a new node. 33 | cluster_node = std::make_shared(); 34 | node_map_.insert(std::make_pair(resource_name, cluster_node)); 35 | 36 | SENTINEL_LOG(info, "Creating resource node for <{}>", resource_name); 37 | } else { 38 | cluster_node = got->second; 39 | } 40 | } // write lock end 41 | return cluster_node; 42 | } 43 | 44 | void ResourceNodeStorage::ResetClusterNodes() { 45 | absl::WriterMutexLock lck(&node_map_mtx_); 46 | for (const auto& e : node_map_) { 47 | e.second->Reset(); 48 | } 49 | } 50 | 51 | const std::unordered_map 52 | ResourceNodeStorage::GetNodeMap() const { 53 | absl::ReaderMutexLock lck(&node_map_mtx_); 54 | return this->node_map_; 55 | } 56 | 57 | } // namespace Stat 58 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/statistic/node/resource_node_storage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "sentinel-core/statistic/node/cluster_node.h" 7 | 8 | #include "absl/synchronization/mutex.h" 9 | 10 | namespace Sentinel { 11 | namespace Stat { 12 | 13 | class ResourceNodeStorage { 14 | public: 15 | ~ResourceNodeStorage() = default; 16 | 17 | static ResourceNodeStorage& GetInstance() { 18 | static ResourceNodeStorage* instance = new ResourceNodeStorage(); 19 | return *instance; 20 | } 21 | 22 | Stat::ClusterNodeSharedPtr GetClusterNode( 23 | const std::string& resource_name) const; 24 | Stat::ClusterNodeSharedPtr GetOrCreateClusterNode( 25 | const std::string& resource_name); 26 | void ResetClusterNodes(); 27 | Stat::ClusterNodeSharedPtr GetEntryNode() { return entry_node_; } 28 | 29 | const std::unordered_map GetNodeMap() 30 | const; 31 | 32 | private: 33 | ResourceNodeStorage() { entry_node_ = std::make_shared(); } 34 | 35 | std::unordered_map node_map_; 36 | 37 | // Global statistic node for inbound traffic. Usually used for SystemRule 38 | // checking. 39 | ClusterNodeSharedPtr entry_node_; 40 | 41 | mutable absl::Mutex node_map_mtx_; // protect `node_map_` 42 | }; 43 | 44 | } // namespace Stat 45 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/system/system_rule.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/system/system_rule.h" 2 | #include "absl/strings/str_format.h" 3 | 4 | namespace Sentinel { 5 | namespace System { 6 | 7 | std::string GetMetricTypeString(MetricType ruleType) { 8 | switch (ruleType) { 9 | case MetricType::kQps: 10 | return std::string("qps"); 11 | case MetricType::kConcurrency: 12 | return std::string("concurrency"); 13 | case MetricType::kRt: 14 | return std::string("rt"); 15 | case MetricType::kCpuUsage: 16 | return std::string("cpu_usage"); 17 | case MetricType::kSystemLoad: 18 | return std::string("system_load"); 19 | default: 20 | return absl::StrFormat("unknown_type(%d)", ruleType); 21 | } 22 | } 23 | 24 | // Sentinel::Property::SentinelProperty. need this 25 | bool SystemRule::operator==(const SystemRule &rule) const { 26 | return metric_type_ == rule.metric_type() && threshold_ == rule.threshold(); 27 | } 28 | 29 | std::string SystemRule::ToString() const { 30 | return absl::StrFormat("SystemRule{metric_type=%s, threshold=%.2lf}", 31 | GetMetricTypeString(metric_type_).c_str(), threshold_); 32 | } 33 | 34 | } // namespace System 35 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/system/system_rule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "absl/strings/str_format.h" 10 | #include "absl/synchronization/mutex.h" 11 | #include "sentinel-core/common/rule.h" 12 | 13 | namespace Sentinel { 14 | namespace System { 15 | 16 | enum MetricType { kSystemLoad = 0, kRt, kConcurrency, kQps, kCpuUsage }; 17 | 18 | std::string GetMetricTypeString(MetricType ruleType); 19 | 20 | struct SystemRule : public Rule { 21 | public: 22 | SystemRule() = default; 23 | SystemRule(MetricType metric_type, double threshold) 24 | : metric_type_(metric_type), threshold_(threshold) {} 25 | virtual ~SystemRule() = default; 26 | 27 | void set_rule_type(MetricType r_t_) { metric_type_ = r_t_; } 28 | void set_threshold(double t_) { threshold_ = t_; } 29 | MetricType metric_type() const { return metric_type_; } 30 | double threshold() const { return threshold_; } 31 | 32 | bool operator==(const SystemRule& rule) const; 33 | std::string ToString() const; 34 | 35 | private: 36 | MetricType metric_type_; 37 | double threshold_; 38 | }; 39 | 40 | using SystemRuleSharedPtr = std::shared_ptr; 41 | using SystemRuleList = std::vector; 42 | 43 | } // namespace System 44 | } // namespace Sentinel 45 | 46 | namespace std { 47 | template <> 48 | struct hash { 49 | size_t operator()(const Sentinel::System::MetricType& t) const { 50 | return hash{}(static_cast(t)); 51 | } 52 | }; 53 | } // namespace std -------------------------------------------------------------------------------- /sentinel-core/system/system_slot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sentinel-core/slot/base/rule_checker_slot.h" 4 | #include "sentinel-core/system/system_rule_manager.h" 5 | 6 | namespace Sentinel { 7 | namespace Slot { 8 | 9 | constexpr auto kSystemSlotName = "SystemSlot"; 10 | 11 | class SystemSlot : public RuleCheckerSlot { 12 | public: 13 | SystemSlot() = default; 14 | virtual ~SystemSlot() = default; 15 | 16 | TokenResultSharedPtr Entry(const EntrySharedPtr& entry, 17 | Stat::NodeSharedPtr& node, int count, int flag, 18 | const std::vector& params) override; 19 | void Exit(const EntrySharedPtr& entry, int count, 20 | const std::vector& params) override; 21 | const std::string& Name() const override; 22 | TokenResultSharedPtr CheckSystem( 23 | const System::SystemRuleMapSharedPtr sysRuleMap, 24 | Stat::NodeSharedPtr& node, int acquire_count) const; 25 | virtual double GetCurCpuUsage() const { 26 | return System::SystemStatusListener::GetInstance().GetCurCpuUsage(); 27 | } 28 | virtual double GetCurLoad() const { 29 | return System::SystemStatusListener::GetInstance().GetCurLoad(); 30 | } 31 | friend class System::SystemRuleManager; 32 | 33 | private: 34 | const std::string name_{kSystemSlotName}; 35 | System::SystemRuleManager& sysMgr = System::SystemRuleManager::GetInstance(); 36 | bool CheckBbr(double curThread, Stat::NodeSharedPtr& node) const; 37 | }; 38 | 39 | } // namespace Slot 40 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/system/system_slot_mock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gmock/gmock.h" 4 | #include "gtest/gtest.h" 5 | 6 | #include "sentinel-core/common/string_resource_wrapper.h" 7 | #include "sentinel-core/slot/base/token_result.h" 8 | #include "sentinel-core/statistic/node/node.h" 9 | #include "sentinel-core/statistic/node/statistic_node.h" 10 | #include "sentinel-core/system/system_rule.h" 11 | #include "sentinel-core/system/system_rule_manager.h" 12 | #include "sentinel-core/system/system_slot.h" 13 | 14 | namespace Sentinel { 15 | namespace Slot { 16 | class MockSystemSlot : public SystemSlot { 17 | public: 18 | MockSystemSlot() = default; 19 | ~MockSystemSlot() = default; 20 | MOCK_METHOD6(Entry, TokenResultSharedPtr(const EntrySharedPtr&, 21 | const ResourceWrapperSharedPtr&, 22 | Stat::NodeSharedPtr&, int, int, 23 | const std::vector&)); 24 | MOCK_METHOD4(Exit, 25 | void(const EntrySharedPtr&, const ResourceWrapperSharedPtr&, int, 26 | const std::vector&)); 27 | MOCK_CONST_METHOD3(CheckSystem, 28 | TokenResultSharedPtr(const System::SystemRuleMapSharedPtr, 29 | Stat::NodeSharedPtr&, int)); 30 | MOCK_CONST_METHOD0(GetCurCpuUsage, double(void)); 31 | MOCK_CONST_METHOD0(GetCurLoad, double(void)); 32 | MOCK_CONST_METHOD0(Name, const std::string&(void)); 33 | 34 | TokenResultSharedPtr OriginalCheckSystem( 35 | const System::SystemRuleMapSharedPtr sysRuleMap, 36 | Stat::NodeSharedPtr& node, int acquire_count) const { 37 | return SystemSlot::CheckSystem(sysRuleMap, node, acquire_count); 38 | } 39 | }; 40 | 41 | } // namespace Slot 42 | } // namespace Sentinel 43 | -------------------------------------------------------------------------------- /sentinel-core/system/system_status_listener_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "gmock/gmock.h" 4 | #include "gtest/gtest.h" 5 | 6 | #include "sentinel-core/system/system_rule_manager.h" 7 | #include "sentinel-core/system/system_status_listener.h" 8 | 9 | namespace Sentinel { 10 | namespace System { 11 | 12 | TEST(SystemStatusListenerTest, SystemStatusListenerSingleThreadTest) { 13 | SystemStatusListener::GetInstance().Initialize(); 14 | 15 | // If the listening thread hasn't finished its first loop when code gets here, 16 | // the read-out properties still remain the initial value(-1) 17 | EXPECT_GE(SystemStatusListener::GetInstance().GetCurCpuUsage(), -1); 18 | EXPECT_GE(SystemStatusListener::GetInstance().GetCurLoad(), -1); 19 | } 20 | 21 | } // namespace System 22 | } // namespace Sentinel 23 | -------------------------------------------------------------------------------- /sentinel-core/test/mock/common/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | package(default_visibility = ["//visibility:public"]) 3 | 4 | cc_library( 5 | name = "mock_lib", 6 | srcs = [ 7 | "mock.h", 8 | "mock.cc", 9 | ], 10 | copts = TEST_COPTS, 11 | deps = [ 12 | "//sentinel-core/common:rule_lib", 13 | "@com_google_googletest//:gtest", 14 | ] 15 | ) -------------------------------------------------------------------------------- /sentinel-core/test/mock/common/mock.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba/sentinel-cpp/36871db9cc0ca76b9bdf666f0a99f41bb026abfc/sentinel-core/test/mock/common/mock.cc -------------------------------------------------------------------------------- /sentinel-core/test/mock/common/mock.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "gmock/gmock.h" 7 | #include "gtest/gtest.h" 8 | 9 | #include "sentinel-core/common/rule.h" 10 | 11 | namespace Sentinel { 12 | 13 | class FakeRule : public Rule { 14 | public: 15 | FakeRule() = default; 16 | 17 | void set_fake_rule_data(const std::string& data) { fake_rule_data_ = data; } 18 | const std::string& fake_rule_data() const { return fake_rule_data_; } 19 | 20 | bool operator==(const FakeRule& other) const { 21 | return fake_rule_data_ == other.fake_rule_data(); 22 | } 23 | 24 | private: 25 | std::string fake_rule_data_; 26 | }; 27 | 28 | } // namespace Sentinel 29 | -------------------------------------------------------------------------------- /sentinel-core/test/mock/flow/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | package(default_visibility = ["//visibility:public"]) 3 | 4 | cc_library( 5 | name = "flow_mock_lib", 6 | srcs = [ 7 | "mock.h", 8 | "mock.cc", 9 | ], 10 | copts = TEST_COPTS, 11 | deps = [ 12 | "//sentinel-core/flow:traffic_shaping_calculator_interface", 13 | "//sentinel-core/flow:traffic_shaping_checker_interface", 14 | "@com_google_googletest//:gtest", 15 | ] 16 | ) -------------------------------------------------------------------------------- /sentinel-core/test/mock/flow/mock.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/test/mock/flow/mock.h" 2 | 3 | namespace Sentinel { 4 | namespace Flow { 5 | 6 | MockTrafficShapingChecker::MockTrafficShapingChecker() = default; 7 | MockTrafficShapingChecker::~MockTrafficShapingChecker() = default; 8 | 9 | MockTrafficShapingCalculator::MockTrafficShapingCalculator() = default; 10 | MockTrafficShapingCalculator::~MockTrafficShapingCalculator() = default; 11 | 12 | } // namespace Flow 13 | } // namespace Sentinel 14 | -------------------------------------------------------------------------------- /sentinel-core/test/mock/flow/mock.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "gmock/gmock.h" 5 | #include "gtest/gtest.h" 6 | 7 | #include "sentinel-core/flow/traffic_shaping_calculator.h" 8 | #include "sentinel-core/flow/traffic_shaping_checker.h" 9 | 10 | namespace Sentinel { 11 | namespace Flow { 12 | 13 | class AlwaysPassChecker : public TrafficShapingChecker { 14 | public: 15 | AlwaysPassChecker() = default; 16 | ~AlwaysPassChecker() = default; 17 | 18 | Slot::TokenResultSharedPtr DoCheck(const Stat::NodeSharedPtr& node, 19 | int acquire_count, double threshold) { 20 | return Slot::TokenResult::Ok(); 21 | } 22 | }; 23 | 24 | class AlwaysBlockChecker : public TrafficShapingChecker { 25 | public: 26 | AlwaysBlockChecker() = default; 27 | ~AlwaysBlockChecker() = default; 28 | 29 | Slot::TokenResultSharedPtr DoCheck(const Stat::NodeSharedPtr& node, 30 | int acquire_count, double threshold) { 31 | return Slot::TokenResult::Blocked("block"); 32 | } 33 | }; 34 | 35 | class MockTrafficShapingChecker : public TrafficShapingChecker { 36 | public: 37 | MockTrafficShapingChecker(); 38 | ~MockTrafficShapingChecker(); 39 | 40 | MOCK_METHOD3(DoCheck, Slot::TokenResultSharedPtr(const Stat::NodeSharedPtr&, 41 | int, double)); 42 | }; 43 | 44 | class MockTrafficShapingCalculator : public TrafficShapingCalculator { 45 | public: 46 | MockTrafficShapingCalculator(); 47 | ~MockTrafficShapingCalculator(); 48 | 49 | MOCK_METHOD3(CalculateAllowedTokens, 50 | double(const Stat::NodeSharedPtr&, int, int)); 51 | }; 52 | 53 | } // namespace Flow 54 | } // namespace Sentinel 55 | -------------------------------------------------------------------------------- /sentinel-core/test/mock/init/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | package(default_visibility = ["//visibility:public"]) 3 | 4 | cc_library( 5 | name = "mock_lib", 6 | srcs = [ 7 | "mock.h", 8 | ], 9 | copts = TEST_COPTS, 10 | deps = [ 11 | "//sentinel-core/init:init_target_interface", 12 | "@com_google_googletest//:gtest", 13 | ] 14 | ) -------------------------------------------------------------------------------- /sentinel-core/test/mock/init/mock.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "gmock/gmock.h" 5 | #include "gtest/gtest.h" 6 | 7 | #include "sentinel-core/init/init_target.h" 8 | 9 | namespace Sentinel { 10 | namespace Init { 11 | 12 | class FakeInitTarget : public Target { 13 | public: 14 | FakeInitTarget() = default; 15 | ~FakeInitTarget() = default; 16 | 17 | void Initialize() { count_ = 1; } 18 | int count() const { return count_; } 19 | 20 | private: 21 | int count_; 22 | }; 23 | 24 | class MockInitTarget : public Target { 25 | public: 26 | MockInitTarget() = default; 27 | ~MockInitTarget() = default; 28 | 29 | MOCK_METHOD0(Initialize, void()); 30 | }; 31 | 32 | } // namespace Init 33 | } // namespace Sentinel 34 | -------------------------------------------------------------------------------- /sentinel-core/test/mock/property/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | package(default_visibility = ["//visibility:public"]) 3 | 4 | cc_library( 5 | name = "mock_lib", 6 | srcs = [ 7 | "mock.h", 8 | "mock.cc", 9 | ], 10 | copts = TEST_COPTS, 11 | deps = [ 12 | "//sentinel-core/property:property_listener_interface", 13 | "@com_google_googletest//:gtest", 14 | ] 15 | ) -------------------------------------------------------------------------------- /sentinel-core/test/mock/property/mock.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/test/mock/property/mock.h" 2 | 3 | namespace Sentinel { 4 | namespace Property {} // namespace Property 5 | } // namespace Sentinel 6 | -------------------------------------------------------------------------------- /sentinel-core/test/mock/property/mock.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "gmock/gmock.h" 5 | #include "gtest/gtest.h" 6 | 7 | #include "sentinel-core/property/property_listener.h" 8 | 9 | namespace Sentinel { 10 | namespace Property { 11 | 12 | template 13 | class MockPropertyListener : public PropertyListener { 14 | public: 15 | MockPropertyListener() = default; 16 | ~MockPropertyListener() = default; 17 | 18 | MOCK_METHOD2_T(ConfigUpdate, void(const T&, bool)); 19 | const std::string Name() const override { return "MockPropertyListener"; } 20 | }; 21 | 22 | } // namespace Property 23 | } // namespace Sentinel 24 | -------------------------------------------------------------------------------- /sentinel-core/test/mock/slot/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | package(default_visibility = ["//visibility:public"]) 3 | 4 | cc_library( 5 | name = "mock_lib", 6 | srcs = [ 7 | "mock.h", 8 | "mock.cc", 9 | ], 10 | copts = TEST_COPTS, 11 | deps = [ 12 | "//sentinel-core/slot/base:rule_checker_slot_interface", 13 | "//sentinel-core/slot/base:stats_slot_interface", 14 | "//sentinel-core/slot/base:slot_interface", 15 | "//sentinel-core/slot/base:default_slot_chain_impl_lib", 16 | "@com_google_googletest//:gtest", 17 | ] 18 | ) -------------------------------------------------------------------------------- /sentinel-core/test/mock/slot/mock.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/test/mock/slot/mock.h" 2 | 3 | namespace Sentinel { 4 | namespace Slot { 5 | MockRuleCheckerSlot::MockRuleCheckerSlot() = default; 6 | MockRuleCheckerSlot::~MockRuleCheckerSlot() = default; 7 | 8 | MockStatsSlot::MockStatsSlot() = default; 9 | MockStatsSlot::~MockStatsSlot() = default; 10 | 11 | } // namespace Slot 12 | } // namespace Sentinel 13 | -------------------------------------------------------------------------------- /sentinel-core/test/mock/slot/mock.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "gmock/gmock.h" 5 | #include "gtest/gtest.h" 6 | 7 | #include "sentinel-core/slot/base/rule_checker_slot.h" 8 | #include "sentinel-core/slot/base/stats_slot.h" 9 | #include "sentinel-core/slot/base/token_result.h" 10 | 11 | namespace Sentinel { 12 | namespace Slot { 13 | 14 | class MockRuleCheckerSlot : public RuleCheckerSlot { 15 | public: 16 | MockRuleCheckerSlot(); 17 | ~MockRuleCheckerSlot(); 18 | MOCK_METHOD5(Entry, TokenResultSharedPtr(const EntrySharedPtr &, 19 | Stat::NodeSharedPtr &, int, int, 20 | const std::vector &)); 21 | MOCK_METHOD3(Exit, void(const EntrySharedPtr &, int, 22 | const std::vector &)); 23 | MOCK_CONST_METHOD0(Name, const std::string &(void)); 24 | }; 25 | 26 | class MockStatsSlot : public StatsSlot { 27 | public: 28 | MockStatsSlot(); 29 | ~MockStatsSlot(); 30 | MOCK_METHOD5(Entry, TokenResultSharedPtr(const EntrySharedPtr &, 31 | Stat::NodeSharedPtr &, int, int, 32 | const std::vector &)); 33 | MOCK_METHOD3(Exit, void(const EntrySharedPtr &, int, 34 | const std::vector &)); 35 | MOCK_CONST_METHOD0(Name, const std::string &(void)); 36 | }; 37 | 38 | } // namespace Slot 39 | } // namespace Sentinel 40 | -------------------------------------------------------------------------------- /sentinel-core/test/mock/statistic/base/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | package(default_visibility = ["//visibility:public"]) 3 | 4 | cc_library( 5 | name = "mock_lib", 6 | srcs = [ 7 | "mock.h", 8 | "mock.cc", 9 | ], 10 | copts = TEST_COPTS, 11 | deps = [ 12 | "//sentinel-core/statistic/base:sliding_window_metric_lib", 13 | "@com_google_googletest//:gtest", 14 | ] 15 | ) -------------------------------------------------------------------------------- /sentinel-core/test/mock/statistic/base/mock.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/test/mock/statistic/base/mock.h" 2 | 3 | namespace Sentinel { 4 | namespace Stat {} // namespace Stat 5 | } // namespace Sentinel 6 | -------------------------------------------------------------------------------- /sentinel-core/test/mock/statistic/base/mock.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "gmock/gmock.h" 5 | #include "gtest/gtest.h" 6 | 7 | #include "sentinel-core/statistic/base/bucket_leap_array.h" 8 | 9 | namespace Sentinel { 10 | namespace Stat {} // namespace Stat 11 | } // namespace Sentinel 12 | -------------------------------------------------------------------------------- /sentinel-core/test/mock/statistic/node/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | package(default_visibility = ["//visibility:public"]) 3 | 4 | cc_library( 5 | name = "mock_lib", 6 | srcs = [ 7 | "mock.h", 8 | "mock.cc", 9 | ], 10 | copts = TEST_COPTS, 11 | deps = [ 12 | "//sentinel-core/statistic/node:node_interface", 13 | "@com_google_googletest//:gtest", 14 | ] 15 | ) -------------------------------------------------------------------------------- /sentinel-core/test/mock/statistic/node/mock.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/test/mock/statistic/node/mock.h" 2 | 3 | namespace Sentinel { 4 | namespace Stat { 5 | 6 | MockNode::MockNode() = default; 7 | MockNode::~MockNode() = default; 8 | 9 | } // namespace Stat 10 | } // namespace Sentinel 11 | -------------------------------------------------------------------------------- /sentinel-core/test/mock/statistic/node/mock.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "gmock/gmock.h" 5 | #include "gtest/gtest.h" 6 | 7 | #include "sentinel-core/statistic/node/node.h" 8 | 9 | namespace Sentinel { 10 | namespace Stat { 11 | 12 | class MockNode : public Node { 13 | public: 14 | MockNode(); 15 | ~MockNode(); 16 | MOCK_METHOD0(TotalCountInMinute, int64_t(void)); 17 | MOCK_METHOD0(PassCountInMinute, int64_t(void)); 18 | MOCK_METHOD0(CompleteCountInMinute, int64_t(void)); 19 | MOCK_METHOD0(BlockCountInMinute, int64_t(void)); 20 | MOCK_METHOD0(ExceptionCountInMinute, int64_t(void)); 21 | 22 | MOCK_METHOD0(PassQps, double(void)); 23 | MOCK_METHOD0(BlockQps, double(void)); 24 | MOCK_METHOD0(TotalQps, double(void)); 25 | MOCK_METHOD0(CompleteQps, double(void)); 26 | MOCK_METHOD0(MaxCompleteQps, double(void)); 27 | MOCK_METHOD0(ExceptionQps, double(void)); 28 | 29 | MOCK_METHOD0(AvgRt, double(void)); 30 | MOCK_METHOD0(MinRt, double(void)); 31 | MOCK_CONST_METHOD0(CurThreadNum, uint32_t(void)); 32 | 33 | MOCK_METHOD0(Metrics, std::unordered_map(void)); 34 | 35 | MOCK_METHOD0(PreviousBlockQps, double(void)); 36 | MOCK_METHOD0(PreviousPassQps, double(void)); 37 | 38 | MOCK_METHOD1(AddPassRequest, void(int32_t)); 39 | MOCK_METHOD2(AddRtAndCompleteRequest, void(int32_t, int)); 40 | MOCK_METHOD1(AddBlockRequest, void(int32_t)); 41 | MOCK_METHOD1(AddExceptionRequest, void(int32_t)); 42 | MOCK_METHOD0(IncreaseThreadNum, void(void)); 43 | MOCK_METHOD0(DecreaseThreadNum, void(void)); 44 | MOCK_METHOD0(Reset, void(void)); 45 | }; 46 | 47 | } // namespace Stat 48 | } // namespace Sentinel 49 | -------------------------------------------------------------------------------- /sentinel-core/transport/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | cc_library( 6 | name = "transport_constants", 7 | copts = DEFAULT_COPTS, 8 | srcs = [ 9 | "constants.h", 10 | ], 11 | visibility = ["//visibility:public"], 12 | ) -------------------------------------------------------------------------------- /sentinel-core/transport/command/command_handler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/transport/command/command_request.h" 6 | #include "sentinel-core/transport/command/command_response.h" 7 | 8 | namespace Sentinel { 9 | namespace Transport { 10 | 11 | class CommandHandler { 12 | public: 13 | CommandHandler(const std::string& name) : command_name_(name) {} 14 | virtual ~CommandHandler() = default; 15 | virtual CommandResponsePtr Handle(const CommandRequest& request) = 0; 16 | 17 | const std::string& command_name() const { return command_name_; } 18 | 19 | protected: 20 | std::string command_name_; 21 | }; 22 | 23 | using CommandHandlerPtr = std::unique_ptr; 24 | 25 | } // namespace Transport 26 | } // namespace Sentinel 27 | -------------------------------------------------------------------------------- /sentinel-core/transport/command/command_request.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/transport/command/command_request.h" 2 | 3 | namespace Sentinel { 4 | namespace Transport { 5 | 6 | const std::string& CommandRequest::body() const { return body_; } 7 | 8 | CommandRequest& CommandRequest::set_body(const std::string& body) { 9 | body_ = body; 10 | return *this; 11 | } 12 | 13 | const std::unordered_map& 14 | CommandRequest::GetParameters() const { 15 | return parameters_; 16 | } 17 | 18 | std::string CommandRequest::GetParam(const std::string& key) const { 19 | auto it = parameters_.find(key); 20 | if (it == parameters_.end()) { 21 | return std::string(""); 22 | } 23 | 24 | return it->second; 25 | } 26 | 27 | std::string CommandRequest::GetParam(const std::string& key, 28 | const std::string& defaultValue) const { 29 | auto it = parameters_.find(key); 30 | if (it == parameters_.end()) { 31 | return defaultValue; 32 | } 33 | 34 | return it->second; 35 | } 36 | 37 | CommandRequest& CommandRequest::AddParam(const std::string& key, 38 | const std::string& value) { 39 | if (key.size() == 0) { 40 | // logerror 41 | } else { 42 | parameters_[key] = value; 43 | } 44 | 45 | return *this; 46 | } 47 | 48 | CommandRequest& CommandRequest::AddMetadata(const std::string& key, 49 | const std::string& value) { 50 | if (key.size() == 0) { 51 | // logerror 52 | } else { 53 | metadata_[key] = value; 54 | } 55 | return *this; 56 | } 57 | 58 | std::string CommandRequest::GetMetadata(const std::string& key) const { 59 | auto it = metadata_.find(key); 60 | if (it == metadata_.end()) { 61 | return std::string(""); 62 | } 63 | 64 | return it->second; 65 | } 66 | 67 | } // namespace Transport 68 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/command/command_request.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace Sentinel { 7 | namespace Transport { 8 | 9 | class CommandRequest { 10 | public: 11 | const std::string& body() const; 12 | CommandRequest& set_body(const std::string& body); 13 | 14 | CommandRequest& AddParam(const std::string& key, const std::string& value); 15 | std::string GetParam(const std::string& key) const; 16 | std::string GetParam(const std::string& key, 17 | const std::string& defaultValue) const; 18 | const std::unordered_map& GetParameters() const; 19 | 20 | CommandRequest& AddMetadata(const std::string& key, const std::string& value); 21 | std::string GetMetadata(const std::string& key) const; 22 | 23 | private: 24 | std::unordered_map metadata_; 25 | std::unordered_map parameters_; 26 | std::string body_; 27 | }; 28 | 29 | constexpr char kRequestTarget[] = "command-target"; 30 | 31 | } // namespace Transport 32 | } // namespace Sentinel 33 | -------------------------------------------------------------------------------- /sentinel-core/transport/command/command_request_test.cc: -------------------------------------------------------------------------------- 1 | #include "gmock/gmock.h" 2 | #include "gtest/gtest.h" 3 | 4 | #define private public 5 | 6 | #include "sentinel-core/transport/command/command_request.h" 7 | 8 | namespace Sentinel { 9 | namespace Transport { 10 | 11 | TEST(CommandRequestTest, TestBody) { 12 | CommandRequest request; 13 | 14 | request.set_body("testbody"); 15 | auto ret = request.body(); 16 | 17 | EXPECT_EQ(ret, "testbody"); 18 | } 19 | 20 | TEST(CommandRequestTest, TestParam) { 21 | CommandRequest request; 22 | 23 | request.AddParam("key1", "val1"); 24 | request.AddParam("key2", "val2"); 25 | 26 | auto v1 = request.GetParam("key1"); 27 | EXPECT_EQ(v1, "val1"); 28 | 29 | auto v2 = request.GetParam("key2"); 30 | EXPECT_EQ(v2, "val2"); 31 | 32 | auto v3 = request.GetParam("key3"); 33 | EXPECT_EQ(v3, ""); 34 | 35 | auto v4 = request.GetParam("key4", "defaultVal"); 36 | EXPECT_EQ(v4, "defaultVal"); 37 | } 38 | 39 | TEST(CommandRequestTest, TestMetadata) { 40 | CommandRequest request; 41 | 42 | request.AddMetadata("key1", "val1"); 43 | request.AddMetadata("key2", "val2"); 44 | 45 | auto v1 = request.GetMetadata("key1"); 46 | EXPECT_EQ(v1, "val1"); 47 | 48 | auto v2 = request.GetMetadata("key2"); 49 | EXPECT_EQ(v2, "val2"); 50 | 51 | auto v3 = request.GetMetadata("key3"); 52 | EXPECT_EQ(v3, ""); 53 | } 54 | 55 | } // namespace Transport 56 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/command/command_response.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace Sentinel { 7 | namespace Transport { 8 | 9 | class CommandResponse; 10 | using CommandResponseSharedPtr = std::shared_ptr; 11 | using CommandResponsePtr = std::unique_ptr; 12 | 13 | class CommandResponse { 14 | public: 15 | CommandResponse(bool success, const std::string& result) 16 | : success_(success), result_(result) {} 17 | 18 | static CommandResponsePtr OfSuccess(const std::string& result) { 19 | return std::make_unique(true, result); 20 | } 21 | 22 | static CommandResponsePtr OfFailure(const std::string& result) { 23 | return std::make_unique(false, result); 24 | } 25 | 26 | bool success() const { return success_; } 27 | const std::string& result() const { return result_; } 28 | 29 | private: 30 | bool success_; 31 | std::string result_; 32 | }; 33 | 34 | } // namespace Transport 35 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/command/handler/fetch_cluster_node_handler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/transport/command/command_handler.h" 6 | 7 | namespace Sentinel { 8 | namespace Transport { 9 | 10 | class FetchClusterNodeCommandHandler : public CommandHandler { 11 | public: 12 | FetchClusterNodeCommandHandler() : CommandHandler("clusterNode") {} 13 | 14 | virtual ~FetchClusterNodeCommandHandler() = default; 15 | CommandResponsePtr Handle(const CommandRequest& request) override; 16 | }; 17 | 18 | } // namespace Transport 19 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/command/handler/fetch_cluster_node_handler_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "gmock/gmock.h" 4 | #include "gtest/gtest.h" 5 | 6 | #include "sentinel-core/transport/command/handler/fetch_cluster_node_handler.h" 7 | 8 | using testing::_; 9 | using testing::InSequence; 10 | using testing::Return; 11 | 12 | namespace Sentinel { 13 | namespace Stat { 14 | 15 | TEST(FetchClusterNodeHandlerTest, TestBasic) {} 16 | 17 | } // namespace Stat 18 | } // namespace Sentinel 19 | -------------------------------------------------------------------------------- /sentinel-core/transport/command/handler/fetch_metric_log_handler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "sentinel-core/config/local_config.h" 7 | #include "sentinel-core/log/log_base.h" 8 | #include "sentinel-core/log/metric/metric_searcher.h" 9 | #include "sentinel-core/log/metric/metric_writer.h" 10 | #include "sentinel-core/transport/command/command_handler.h" 11 | 12 | namespace Sentinel { 13 | namespace Transport { 14 | 15 | class FetchMetricLogCommandHandler : public CommandHandler { 16 | public: 17 | FetchMetricLogCommandHandler() : CommandHandler("metric") { 18 | const std::string& app_name = Config::LocalConfig::GetInstance().app_name(); 19 | searcher_ = std::make_unique( 20 | Log::LogBase::GetLogBaseDir(), 21 | Log::MetricWriter::FormSelfMetricFileName(app_name)); 22 | } 23 | 24 | virtual ~FetchMetricLogCommandHandler() = default; 25 | CommandResponsePtr Handle(const CommandRequest& request) override; 26 | 27 | private: 28 | std::unique_ptr searcher_; 29 | }; 30 | 31 | } // namespace Transport 32 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/command/handler/get_switch_status_handler.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/transport/command/handler/get_switch_status_handler.h" 2 | 3 | #include 4 | 5 | #include "absl/strings/str_format.h" 6 | 7 | #include "sentinel-core/common/global_status.h" 8 | 9 | namespace Sentinel { 10 | namespace Transport { 11 | 12 | CommandResponsePtr GetSwitchStatusCommandHandler::Handle( 13 | const CommandRequest&) { 14 | const char* status = GlobalStatus::activated ? "enabled" : "disabled"; 15 | return CommandResponse::OfSuccess( 16 | absl::StrFormat("Sentinel status: %s", status)); 17 | } 18 | 19 | } // namespace Transport 20 | } // namespace Sentinel 21 | -------------------------------------------------------------------------------- /sentinel-core/transport/command/handler/get_switch_status_handler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/transport/command/command_handler.h" 6 | 7 | namespace Sentinel { 8 | namespace Transport { 9 | 10 | class GetSwitchStatusCommandHandler : public CommandHandler { 11 | public: 12 | GetSwitchStatusCommandHandler() : CommandHandler("getSwitch") {} 13 | 14 | virtual ~GetSwitchStatusCommandHandler() = default; 15 | CommandResponsePtr Handle(const CommandRequest& request) override; 16 | }; 17 | 18 | } // namespace Transport 19 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/command/handler/set_switch_status_handler.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/transport/command/handler/set_switch_status_handler.h" 2 | 3 | #include "sentinel-core/common/global_status.h" 4 | 5 | namespace Sentinel { 6 | namespace Transport { 7 | 8 | CommandResponsePtr SetSwitchStatusCommandHandler::Handle( 9 | const CommandRequest& request) { 10 | auto v = request.GetParam("value"); 11 | if (v == "true") { 12 | GlobalStatus::activated = true; 13 | // SENTINEL_LOG(info, "[SwitchOnOffHandler] Sentinel has been activated"); 14 | return CommandResponse::OfSuccess("Sentinel has been enabled"); 15 | } 16 | if (v == "false") { 17 | GlobalStatus::activated = false; 18 | // SENTINEL_LOG(info, "[SwitchOnOffHandler] Sentinel has been disabled"); 19 | return CommandResponse::OfSuccess("Sentinel has been disabled"); 20 | } 21 | return CommandResponse::OfFailure("bad new status"); 22 | } 23 | 24 | } // namespace Transport 25 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/command/handler/set_switch_status_handler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/transport/command/command_handler.h" 6 | 7 | namespace Sentinel { 8 | namespace Transport { 9 | 10 | class SetSwitchStatusCommandHandler : public CommandHandler { 11 | public: 12 | SetSwitchStatusCommandHandler() : CommandHandler("setSwitch") {} 13 | 14 | virtual ~SetSwitchStatusCommandHandler() = default; 15 | CommandResponsePtr Handle(const CommandRequest& request) override; 16 | }; 17 | 18 | } // namespace Transport 19 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/command/handler/set_switch_status_handler_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "sentinel-core/common/global_status.h" 4 | #include "sentinel-core/transport/command/handler/set_switch_status_handler.h" 5 | 6 | #include "gmock/gmock.h" 7 | #include "gtest/gtest.h" 8 | 9 | namespace Sentinel { 10 | namespace Transport { 11 | 12 | TEST(SetSwitchStatusCommandHandlerTest, TestHandleRequest) { 13 | SetSwitchStatusCommandHandler handler; 14 | CommandRequest request; 15 | EXPECT_FALSE(handler.Handle(request)->success()); 16 | 17 | EXPECT_TRUE(GlobalStatus::activated); 18 | request.AddParam("value", "false"); 19 | EXPECT_TRUE(handler.Handle(request)->success()); 20 | EXPECT_FALSE(GlobalStatus::activated); 21 | 22 | request.AddParam("value", "true"); 23 | EXPECT_TRUE(handler.Handle(request)->success()); 24 | EXPECT_TRUE(GlobalStatus::activated); 25 | } 26 | 27 | } // namespace Transport 28 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/command/handler/version_handler.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/transport/command/handler/version_handler.h" 2 | 3 | #include 4 | 5 | namespace Sentinel { 6 | namespace Transport { 7 | 8 | CommandResponsePtr VersionCommandHandler::Handle( 9 | const CommandRequest& request) { 10 | return CommandResponse::OfSuccess("0.1.0"); 11 | } 12 | 13 | } // namespace Transport 14 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/command/handler/version_handler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sentinel-core/transport/command/command_handler.h" 6 | 7 | namespace Sentinel { 8 | namespace Transport { 9 | 10 | class VersionCommandHandler : public CommandHandler { 11 | public: 12 | VersionCommandHandler() : CommandHandler("version") {} 13 | 14 | virtual ~VersionCommandHandler() = default; 15 | CommandResponsePtr Handle(const CommandRequest& request) override; 16 | }; 17 | 18 | } // namespace Transport 19 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/command/handler/vo/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | cc_library( 6 | name = "statistic_node_vo_lib", 7 | srcs = [ 8 | "statistic_node_vo.h", 9 | "statistic_node_vo.cc", 10 | ], 11 | copts = DEFAULT_COPTS, 12 | deps = [ 13 | "//sentinel-core/statistic/node:cluster_node_lib", 14 | ] 15 | ) 16 | -------------------------------------------------------------------------------- /sentinel-core/transport/command/handler/vo/statistic_node_vo.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "sentinel-core/transport/command/handler/vo/statistic_node_vo.h" 5 | 6 | namespace Sentinel { 7 | namespace Transport { 8 | 9 | std::shared_ptr StatisticNodeVO::FromResourceNode( 10 | const std::string& name, const Stat::ClusterNodeSharedPtr& node) { 11 | if (node == nullptr) { 12 | return nullptr; 13 | } 14 | std::shared_ptr vo = std::make_shared(); 15 | vo->set_resource(name); 16 | vo->set_thread_num(node->CurThreadNum()); 17 | vo->set_pass_qps(node->PassQps()); 18 | vo->set_block_qps(node->BlockQps()); 19 | vo->set_total_qps(node->TotalQps()); 20 | vo->set_avg_rt(node->AvgRt()); 21 | vo->set_complete_qps(node->CompleteQps()); 22 | vo->set_exception_qps(node->ExceptionQps()); 23 | vo->set_pass_per_min(node->PassCountInMinute()); 24 | vo->set_block_per_min(node->BlockCountInMinute()); 25 | vo->set_total_per_min(node->TotalCountInMinute()); 26 | vo->set_exception_per_min(node->ExceptionCountInMinute()); 27 | vo->set_timestamp(Utils::TimeUtils::CurrentTimeMillis().count()); 28 | return vo; 29 | } 30 | 31 | } // namespace Transport 32 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/command/http_command_center.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "sentinel-core/transport/command/command_handler.h" 7 | #include "sentinel-core/transport/command/command_response.h" 8 | #include "sentinel-core/transport/command/http_server.h" 9 | 10 | namespace Sentinel { 11 | namespace Transport { 12 | 13 | class HttpCommandCenter { 14 | public: 15 | explicit HttpCommandCenter() = default; 16 | ~HttpCommandCenter(); 17 | 18 | bool Start(int port); 19 | void Stop(); 20 | 21 | bool RegisterCommand(CommandHandlerPtr&& handler); 22 | 23 | private: 24 | void OnHttpRequest(struct evhttp_request* http_req); 25 | void HandleResponse(struct evhttp_request* http_req, 26 | CommandResponsePtr&& response); 27 | 28 | private: 29 | std::unique_ptr http_server_; 30 | std::unordered_map handler_map_; 31 | }; 32 | 33 | } // namespace Transport 34 | } // namespace Sentinel 35 | -------------------------------------------------------------------------------- /sentinel-core/transport/command/http_command_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "sentinel-core/transport/command/command_request.h" 10 | 11 | namespace Sentinel { 12 | namespace Transport { 13 | 14 | class HttpCommandUtils { 15 | public: 16 | HttpCommandUtils() = delete; 17 | 18 | static void SucessRequest(struct evhttp_request *http_req, 19 | const std::string &msg); 20 | 21 | static void BadRequest(struct evhttp_request *http_req, 22 | const std::string &msg); 23 | 24 | static void InternalError(struct evhttp_request *http_req, 25 | const std::string &msg); 26 | 27 | static CommandRequest ParseHttpRequest(struct evhttp_request *http_req); 28 | 29 | private: 30 | static void ParseRequestUri(const std::string &uri, CommandRequest *request); 31 | static void ParsePostData(struct evhttp_request *http_req, 32 | Sentinel::Transport::CommandRequest *request); 33 | }; 34 | 35 | } // namespace Transport 36 | } // namespace Sentinel 37 | -------------------------------------------------------------------------------- /sentinel-core/transport/command/http_server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | //#include 8 | //#include 9 | #include 10 | 11 | #include "sentinel-core/transport/common/event_loop_thread.h" 12 | 13 | namespace Sentinel { 14 | namespace Transport { 15 | 16 | void HttpCallback(struct evhttp_request *req, void *arg); 17 | using http_request_callback_t = std::function; 18 | 19 | class HttpServer { 20 | public: 21 | HttpServer(http_request_callback_t callback); 22 | ~HttpServer(); 23 | 24 | bool Start(int port); 25 | void Stop(); 26 | 27 | private: 28 | void InternalStart(std::promise &promise); 29 | void OnHttpRequest(struct evhttp_request *req); 30 | 31 | private: 32 | EventLoopThread event_loop_thread_; 33 | 34 | struct evhttp *http_ = nullptr; 35 | http_request_callback_t request_callback_; 36 | 37 | static void HttpGenCallback(struct evhttp_request *req, void *arg); 38 | 39 | private: 40 | int port_; 41 | }; 42 | 43 | } // namespace Transport 44 | } // namespace Sentinel 45 | -------------------------------------------------------------------------------- /sentinel-core/transport/command/http_server_init_target.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "absl/strings/numbers.h" 5 | 6 | #include "sentinel-core/transport/command/handler/fetch_cluster_node_handler.h" 7 | #include "sentinel-core/transport/command/handler/fetch_metric_log_handler.h" 8 | #include "sentinel-core/transport/command/handler/get_switch_status_handler.h" 9 | #include "sentinel-core/transport/command/handler/set_switch_status_handler.h" 10 | #include "sentinel-core/transport/command/handler/version_handler.h" 11 | #include "sentinel-core/transport/command/http_server_init_target.h" 12 | #include "sentinel-core/transport/constants.h" 13 | 14 | namespace Sentinel { 15 | namespace Transport { 16 | 17 | void HttpCommandCenterInitTarget::Close() { 18 | if (!closed_ && command_center_ != nullptr) { 19 | // Not thread-safe 20 | closed_ = true; 21 | command_center_->Stop(); 22 | } 23 | } 24 | 25 | uint32_t HttpCommandCenterInitTarget::GetAvailablePort() { 26 | const char* command_port_env = std::getenv(Constants::kCommandPortKey); 27 | uint32_t port; 28 | if (command_port_env != nullptr) { 29 | if (!absl::SimpleAtoi(command_port_env, &port)) { 30 | port = Constants::kDefaultCommandPort; 31 | } 32 | } else { 33 | port = Constants::kDefaultCommandPort; 34 | } 35 | return port; 36 | } 37 | 38 | void HttpCommandCenterInitTarget::Initialize() { 39 | // Register commands. 40 | command_center_->RegisterCommand( 41 | std::make_unique()); 42 | command_center_->RegisterCommand( 43 | std::make_unique()); 44 | command_center_->RegisterCommand( 45 | std::make_unique()); 46 | command_center_->RegisterCommand( 47 | std::make_unique()); 48 | command_center_->RegisterCommand(std::make_unique()); 49 | 50 | uint32_t port = GetAvailablePort(); 51 | command_center_->Start(port); 52 | } 53 | 54 | } // namespace Transport 55 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/command/http_server_init_target.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "sentinel-core/init/init_target.h" 7 | #include "sentinel-core/transport/command/http_command_center.h" 8 | 9 | namespace Sentinel { 10 | namespace Transport { 11 | 12 | class HttpCommandCenterInitTarget : public Init::Target { 13 | public: 14 | HttpCommandCenterInitTarget() 15 | : command_center_(std::make_unique()) {} 16 | virtual ~HttpCommandCenterInitTarget() = default; 17 | 18 | void Initialize() override; 19 | void Close(); 20 | 21 | private: 22 | uint32_t GetAvailablePort(); 23 | 24 | const std::unique_ptr command_center_; 25 | bool closed_{false}; 26 | }; 27 | 28 | } // namespace Transport 29 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/common/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | cc_library( 6 | name = "transport_common", 7 | copts = DEFAULT_COPTS, 8 | srcs = [ 9 | "event_loop_thread.h", 10 | "event_loop_thread.cc", 11 | ], 12 | deps = [ 13 | "//:libevent", 14 | ], 15 | visibility = ["//visibility:public"], 16 | ) 17 | 18 | 19 | cc_test( 20 | name = "event_loop_thread_unittests", 21 | srcs = [ 22 | "event_loop_thread.cc", 23 | ], 24 | copts = TEST_COPTS, 25 | deps = [ 26 | ":transport_common", 27 | "@com_google_googletest//:gtest_main", 28 | ], 29 | linkstatic = 1, 30 | ) -------------------------------------------------------------------------------- /sentinel-core/transport/common/event_loop_thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | namespace Sentinel { 11 | namespace Transport { 12 | 13 | class EventLoopThread { 14 | using Functor = std::function; 15 | 16 | public: 17 | EventLoopThread(); 18 | ~EventLoopThread() = default; 19 | 20 | bool Start(); 21 | void Stop(); 22 | 23 | struct event_base *GetEventBase(); 24 | 25 | void RunTask(Functor func); 26 | 27 | bool IsInLoopThread() const; 28 | 29 | private: 30 | bool InitEventBase(); 31 | void ClearEventBase(); 32 | 33 | void Dispatch(); 34 | void Work(std::promise &promise); 35 | void Wakeup(); 36 | void DoPendingTasks(); 37 | 38 | static void OnWakeupFdCallback(evutil_socket_t fd, short events, 39 | void *userdata); 40 | 41 | private: 42 | struct event_base *base_ = nullptr; 43 | 44 | std::unique_ptr thd_; 45 | std::atomic stoped_; 46 | evutil_socket_t wakeup_fd_[2]; // 0:read 1:write 47 | 48 | std::mutex task_mutex_; 49 | std::vector pending_tasks_; 50 | }; 51 | 52 | } // namespace Transport 53 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/common/event_loop_thread_test.cc: -------------------------------------------------------------------------------- 1 | #include "gmock/gmock.h" 2 | #include "gtest/gtest.h" 3 | 4 | #define private public 5 | 6 | #include "sentinel-core/transport/common/event_loop_thread.h" 7 | 8 | namespace Sentinel { 9 | namespace Transport { 10 | 11 | TEST(CommandRequestTest, TestStart) { 12 | EventLoopThread loop; 13 | auto ret = loop.Start(); 14 | EXPECT_EQ(ret, true); 15 | EXPECT_EQ(loop.stoped_, false); 16 | EXPECT_NE(loop.thd_->get_id(), std::this_thread::get_id()); 17 | } 18 | 19 | TEST(CommandRequestTest, TestStop) { 20 | EventLoopThread loop; 21 | auto ret = loop.Start(); 22 | EXPECT_EQ(ret, true); 23 | 24 | loop.Stop(); 25 | EXPECT_EQ(loop.stoped_, true); 26 | EXPECT_EQ(loop.thd_->joinable(), false); 27 | } 28 | 29 | TEST(CommandRequestTest, TestRunTask) { 30 | EventLoopThread loop; 31 | auto ret = loop.Start(); 32 | EXPECT_EQ(ret, true); 33 | 34 | std::promise promise; 35 | auto future = promise.get_future(); 36 | 37 | auto task = [&promise]() { promise.set_value(std::this_thread::get_id()); }; 38 | 39 | loop.RunTask(task); 40 | 41 | auto run_task_thread_id = future.get(); 42 | EXPECT_EQ(run_task_thread_id, loop.thd_->get_id()); 43 | 44 | loop.Stop(); 45 | EXPECT_EQ(loop.stoped_, true); 46 | EXPECT_EQ(loop.thd_->joinable(), false); 47 | } 48 | 49 | } // namespace Transport 50 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/transport/constants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace Sentinel { 6 | namespace Transport { 7 | namespace Constants { 8 | 9 | constexpr auto kCommandPortKey = "CSP_SENTINEL_API_PORT"; 10 | constexpr uint32_t kDefaultCommandPort = 8718; 11 | 12 | } // namespace Constants 13 | } // namespace Transport 14 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/utils/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | cc_library( 6 | name = "utils_lib", 7 | srcs = [ 8 | "utils.h", 9 | "utils.cc", 10 | "time_utils.h", 11 | "time_utils.cc", 12 | ], 13 | copts = DEFAULT_COPTS, 14 | ) 15 | 16 | 17 | cc_library( 18 | name = "file_utils_lib", 19 | srcs = [ 20 | "file_utils.h", 21 | "file_utils.cc", 22 | ], 23 | copts = DEFAULT_COPTS, 24 | ) 25 | 26 | cc_library( 27 | name = "macros_lib", 28 | srcs = [ 29 | "macros.h", 30 | ], 31 | copts = DEFAULT_COPTS, 32 | ) -------------------------------------------------------------------------------- /sentinel-core/utils/file_utils.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/utils/file_utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace Sentinel { 14 | namespace Utils { 15 | 16 | bool FileUtils::FileExists(const std::string& path) { 17 | std::ifstream input_file(path); 18 | return input_file.is_open(); 19 | } 20 | 21 | bool FileUtils::DirExists(const std::string& path) { 22 | DIR* const dir = ::opendir(path.c_str()); 23 | 24 | bool dir_exists = (nullptr != dir); 25 | if (dir_exists) { 26 | ::closedir(dir); 27 | } 28 | 29 | return dir_exists; 30 | } 31 | 32 | bool FileUtils::CreateDir(const std::string& path) { 33 | auto s = path; 34 | size_t pos = 0; 35 | std::string dir; 36 | int ret; 37 | 38 | if (s[s.size() - 1] != '/') { 39 | s += '/'; 40 | } 41 | 42 | while ((pos = s.find_first_of('/', pos)) != std::string::npos) { 43 | dir = s.substr(0, pos++); 44 | if (dir.size() == 0) { 45 | continue; // if leading / first time is 0 length 46 | } 47 | if ((ret = mkdir(dir.c_str(), S_IRWXU)) && errno != EEXIST) { 48 | return ret == 0; 49 | } 50 | } 51 | return ret == 0; 52 | } 53 | 54 | std::vector FileUtils::ListFiles(const std::string& path) { 55 | std::vector files; 56 | 57 | auto* dir = opendir(path.c_str()); 58 | if (dir == nullptr) { 59 | return files; 60 | } 61 | 62 | struct dirent* ent; 63 | while ((ent = readdir(dir)) != nullptr) { 64 | files.emplace_back(std::move(ent->d_name)); 65 | } 66 | closedir(dir); 67 | 68 | return files; 69 | } 70 | 71 | std::string FileUtils::GetAbsolutePath(const std::string& path) { 72 | char abs_path[8192] = {0}; 73 | if (realpath(path.c_str(), abs_path) != nullptr) { 74 | return std::string(abs_path); 75 | } 76 | 77 | return ""; 78 | } 79 | 80 | } // namespace Utils 81 | } // namespace Sentinel 82 | -------------------------------------------------------------------------------- /sentinel-core/utils/file_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace Sentinel { 7 | namespace Utils { 8 | 9 | class FileUtils { 10 | public: 11 | FileUtils() = delete; 12 | 13 | static bool FileExists(const std::string& path); 14 | static bool DirExists(const std::string& path); 15 | static bool CreateDir(const std::string& path); 16 | static std::vector ListFiles(const std::string& path); 17 | static std::string GetAbsolutePath(const std::string& path); 18 | }; 19 | 20 | } // namespace Utils 21 | } // namespace Sentinel 22 | -------------------------------------------------------------------------------- /sentinel-core/utils/macros.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace Sentinel { 5 | 6 | #define SENTINEL_PANIC(X) \ 7 | std::cerr << "panic: " << X << std::endl; \ 8 | abort(); 9 | 10 | #define SENTINEL_NOT_IMPLEMENTED_GCOVR_EXCL_LINE \ 11 | SENTINEL_PANIC("not implemented") 12 | #define SENTINEL_NOT_REACHED_GCOVR_EXCL_LINE SENTINEL_PANIC("not reached") 13 | 14 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-core/utils/time_utils.cc: -------------------------------------------------------------------------------- 1 | #include "sentinel-core/utils/time_utils.h" 2 | 3 | namespace Sentinel { 4 | namespace Utils { 5 | 6 | std::chrono::milliseconds TimeUtils::CurrentTimeMillis() { 7 | return std::chrono::duration_cast( 8 | std::chrono::system_clock::now().time_since_epoch()); 9 | } 10 | 11 | } // namespace Utils 12 | } // namespace Sentinel 13 | -------------------------------------------------------------------------------- /sentinel-core/utils/time_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace Sentinel { 6 | namespace Utils { 7 | 8 | class TimeUtils { 9 | public: 10 | TimeUtils() = delete; 11 | 12 | static std::chrono::milliseconds CurrentTimeMillis(); 13 | }; 14 | 15 | } // namespace Utils 16 | } // namespace Sentinel 17 | -------------------------------------------------------------------------------- /sentinel-core/utils/utils.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba/sentinel-cpp/36871db9cc0ca76b9bdf666f0a99f41bb026abfc/sentinel-core/utils/utils.cc -------------------------------------------------------------------------------- /sentinel-core/utils/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Sentinel { 4 | namespace Utils { 5 | 6 | template 7 | class Singleton { 8 | public: 9 | /** 10 | * Obtain an instance of the singleton for class T. 11 | * @return const T& a reference to the singleton for class T. 12 | */ 13 | static T& get() { 14 | static T* instance = new T(); 15 | return *instance; 16 | } 17 | }; 18 | 19 | } // namespace Utils 20 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-datasource-extension/datasource/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | cc_library( 6 | name = "converter_interface", 7 | srcs = [ 8 | "converter.h" 9 | ], 10 | copts = DEFAULT_COPTS, 11 | deps = ["@com_google_absl//absl/types:optional",] 12 | ) 13 | 14 | cc_library( 15 | name = "readable_data_source_interface", 16 | srcs = [ 17 | "readable_data_source.h", 18 | "abstract_readable_data_source.h" 19 | ], 20 | copts = DEFAULT_COPTS, 21 | deps = [ 22 | ":converter_interface", 23 | "//sentinel-core/property:dynamic_sentinel_property_lib" 24 | ] 25 | ) 26 | 27 | cc_test( 28 | name = "abstract_readable_data_source_unittests", 29 | srcs = [ 30 | "abstract_readable_data_source_unittests.cc", 31 | ], 32 | copts = TEST_COPTS, 33 | deps = [ 34 | ":readable_data_source_interface", 35 | ":converter_interface", 36 | "//sentinel-core/test/mock/common:mock_lib", 37 | "//sentinel-core/test/mock/property:mock_lib", 38 | "//sentinel-core/property:dynamic_sentinel_property_lib", 39 | "//sentinel-datasource-extension/test/mock/datasource:mock_lib", 40 | "@com_google_googletest//:gtest_main", 41 | ] 42 | ) -------------------------------------------------------------------------------- /sentinel-datasource-extension/datasource/abstract_readable_data_source.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sentinel-core/property/dynamic_sentinel_property.h" 4 | #include "sentinel-datasource-extension/datasource/converter.h" 5 | #include "sentinel-datasource-extension/datasource/readable_data_source.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace Sentinel { 11 | namespace DataSource { 12 | 13 | template 14 | class AbstractReadableDataSource : public ReadableDataSource { 15 | public: 16 | explicit AbstractReadableDataSource(ConverterSharedPtr converter) 17 | : parser_(converter), 18 | property_(std::make_shared>()) {} 19 | virtual ~AbstractReadableDataSource() = default; 20 | 21 | absl::optional LoadConfig() override { 22 | return Convert(this->ReadSource()); 23 | } 24 | Property::SentinelPropertySharedPtr GetProperty() override { 25 | return property_; 26 | } 27 | 28 | absl::optional Convert(const S& s) { return parser_->Convert(s); } 29 | 30 | private: 31 | ConverterSharedPtr parser_; 32 | Property::SentinelPropertySharedPtr property_; 33 | }; 34 | 35 | } // namespace DataSource 36 | } // namespace Sentinel 37 | -------------------------------------------------------------------------------- /sentinel-datasource-extension/datasource/abstract_readable_data_source_unittests.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "sentinel-datasource-extension/datasource/abstract_readable_data_source.h" 3 | 4 | #include "sentinel-core/test/mock/common/mock.h" 5 | #include "sentinel-core/test/mock/property/mock.h" 6 | #include "sentinel-datasource-extension/test/mock/datasource/mock.h" 7 | 8 | namespace Sentinel { 9 | namespace DataSource { 10 | 11 | using testing::_; 12 | using testing::An; 13 | using testing::InSequence; 14 | using testing::Matcher; 15 | 16 | TEST(AbstractReadableDataSourceTest, Basic) { 17 | auto *convert = new MockConverter(); 18 | 19 | ConverterSharedPtr convert_shared_ptr; 20 | convert_shared_ptr.reset(convert); 21 | 22 | MockAbstractReabableDataSource fake_data_source( 23 | convert_shared_ptr); 24 | FakeRule rule; 25 | rule.set_fake_rule_data("test"); 26 | auto pl = std::make_unique>(); 27 | auto pl_point = pl.get(); 28 | 29 | EXPECT_CALL(*pl_point, ConfigUpdate(Matcher(rule), false)) 30 | .Times(1); 31 | 32 | fake_data_source.GetProperty()->AddListener(std::move(pl)); 33 | fake_data_source.GetProperty()->UpdateValue(rule); 34 | 35 | EXPECT_CALL(*convert, Convert(_)).Times(1); 36 | EXPECT_CALL(fake_data_source, ReadSource()).Times(1); 37 | 38 | fake_data_source.LoadConfig(); 39 | }; 40 | 41 | } // namespace DataSource 42 | } // namespace Sentinel -------------------------------------------------------------------------------- /sentinel-datasource-extension/datasource/converter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "absl/types/optional.h" 6 | 7 | namespace Sentinel { 8 | namespace DataSource { 9 | 10 | template 11 | class Converter { 12 | public: 13 | virtual ~Converter() = default; 14 | virtual absl::optional Convert(const S& source) = 0; 15 | }; 16 | 17 | template 18 | using ConverterSharedPtr = std::shared_ptr>; 19 | 20 | } // namespace DataSource 21 | } // namespace Sentinel 22 | -------------------------------------------------------------------------------- /sentinel-datasource-extension/datasource/readable_data_source.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "absl/types/optional.h" 4 | 5 | #include "sentinel-core/property/sentinel_property.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace Sentinel { 11 | namespace DataSource { 12 | 13 | template 14 | class ReadableDataSource { 15 | public: 16 | virtual ~ReadableDataSource() = default; 17 | virtual absl::optional LoadConfig() = 0; 18 | virtual S ReadSource() = 0; 19 | virtual Property::SentinelPropertySharedPtr GetProperty() = 0; 20 | }; 21 | 22 | } // namespace DataSource 23 | } // namespace Sentinel 24 | -------------------------------------------------------------------------------- /sentinel-datasource-extension/test/mock/datasource/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | package(default_visibility = ["//visibility:public"]) 3 | 4 | cc_library( 5 | name = "mock_lib", 6 | srcs = [ 7 | "mock.h", 8 | "mock.cc", 9 | ], 10 | copts = TEST_COPTS, 11 | deps = [ 12 | "//sentinel-datasource-extension/datasource:converter_interface", 13 | "//sentinel-datasource-extension/datasource:readable_data_source_interface", 14 | "@com_google_googletest//:gtest", 15 | ] 16 | ) -------------------------------------------------------------------------------- /sentinel-datasource-extension/test/mock/datasource/mock.cc: -------------------------------------------------------------------------------- 1 | namespace Sentinel { 2 | namespace DataSource {} // namespace DataSource 3 | } // namespace Sentinel 4 | -------------------------------------------------------------------------------- /sentinel-datasource-extension/test/mock/datasource/mock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "gmock/gmock.h" 6 | #include "gtest/gtest.h" 7 | 8 | #include "sentinel-datasource-extension/datasource/abstract_readable_data_source.h" 9 | #include "sentinel-datasource-extension/datasource/converter.h" 10 | 11 | namespace Sentinel { 12 | namespace DataSource { 13 | 14 | template 15 | class MockConverter : public Converter { 16 | public: 17 | virtual ~MockConverter() = default; 18 | MOCK_METHOD1_T(Convert, absl::optional(const S&)); 19 | }; 20 | 21 | template 22 | class MockAbstractReabableDataSource : public AbstractReadableDataSource { 23 | public: 24 | using AbstractReadableDataSource::AbstractReadableDataSource; 25 | 26 | virtual ~MockAbstractReabableDataSource() = default; 27 | MOCK_METHOD0_T(ReadSource, S()); 28 | }; 29 | 30 | } // namespace DataSource 31 | } // namespace Sentinel 32 | -------------------------------------------------------------------------------- /tests/BUILD: -------------------------------------------------------------------------------- 1 | load("//bazel:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | cc_binary( 5 | name = "tsan-flow", 6 | srcs = ["tsan-flow.cc"], 7 | copts = DEFAULT_COPTS, 8 | deps = [ 9 | "//sentinel-core/public:sph_u_lib", 10 | "//sentinel-core/slot:global_slot_chain_header", 11 | "//sentinel-core/flow:flow_rule_manager_lib", 12 | "//sentinel-core/log:logger_lib", 13 | "//sentinel-core/log/metric:metric_log_task_lib", 14 | "//sentinel-core/statistic/node:resource_node_storage_lib", 15 | "//sentinel-core/init:init_target_registry_lib", 16 | "//sentinel-core/transport/command:http_command_center_init_target", 17 | ], 18 | ) 19 | -------------------------------------------------------------------------------- /third_party/nlohmann/BUILD: -------------------------------------------------------------------------------- 1 | licenses(["notice"]) # Apache 2 2 | 3 | load("//bazel:copts.bzl", "DEFAULT_COPTS") 4 | 5 | package(default_visibility = ["//visibility:public"]) 6 | 7 | cc_library( 8 | name = "nlohmann_json_lib", 9 | srcs = [ 10 | "json.hpp", 11 | ], 12 | copts = DEFAULT_COPTS, 13 | visibility = ["//visibility:public"], 14 | ) 15 | 16 | --------------------------------------------------------------------------------