├── .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 |
2 |
3 | [](https://travis-ci.org/alibaba/sentinel-cpp)
4 | [](https://www.apache.org/licenses/LICENSE-2.0.html)
5 | [](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