diff --git a/.github/actions/coverage/action.yml b/.github/actions/coverage/action.yml
new file mode 100644
index 000000000..7984e365c
--- /dev/null
+++ b/.github/actions/coverage/action.yml
@@ -0,0 +1,111 @@
+#
+# Copyright (c) 2024 Alibaba Group Holding Limited. All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Alibaba designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+name: 'Coverage test'
+
+inputs:
+ reset-commit-id:
+ required: false
+ type: string
+outputs:
+ data:
+ value: ${{ steps.get-cov-report.outputs.data }}
+
+runs:
+ using: composite
+ steps:
+ - name: 'Checkout source code'
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 100
+
+ - name: 'Reset to specific commit'
+ run: |
+ echo "${{ inputs.reset-commit-id }}"
+ git reset --hard ${{ inputs.reset-commit-id }}
+ shell: bash
+ if: ${{ inputs.reset-commit-id }} != ""
+
+ - name: 'Install dependencies'
+ run: |
+ apt --help &>/dev/null
+ if [ $? -eq 0 ];then
+ sudo apt-get install -y openssl libssl-dev llvm jq
+ else
+ yum --help &>/dev/null
+ if [ $? -eq 0 ];then
+ sudo yum install -y openssl openssl-devel llvm jq
+ else
+ exit 1
+ fi
+ fi
+ shell: bash
+
+ - name: 'Install newer clang'
+ run: |
+ apt --help &>/dev/null
+ if [ $? -eq 0 ];then
+ sudo rm /etc/apt/sources.list.d/microsoft-prod.list
+ sudo apt-get update -y
+ else
+ yum --help &>/dev/null
+ [ $? -eq 0 ] && sudo yum update -y
+ fi
+ wget https://apt.llvm.org/llvm.sh -O llvm.sh
+ chmod +x ./llvm.sh
+ sudo ./llvm.sh 17
+ shell: bash
+
+ - name: 'Build and test'
+ id: get-cov-report
+ run: |
+ cp -r src/coro_rpc/tests/openssl_files .
+ rm -rf build
+ mkdir -p build
+ cd build
+ CC=clang-17 CXX=clang++-17 cmake .. -DCOVERAGE_TEST=ON -DYLT_ENABLE_SSL=ON -DBUILD_EXAMPLES=OFF -DBUILD_BENCHMARK=OFF
+ make -j
+ export LLVM_PROFILE_FILE="test_ylt-%m.profraw"
+ cd output/tests
+ find . -maxdepth 1 -type f -executable | xargs -I {} sh -c '{}'
+ llvm-profdata merge -sparse test_ylt-*.profraw -o test_ylt.profdata
+ if [ -n "${{ inputs.reset-commit-id }}" ];then
+ report=base-ylt-cov-report
+ else
+ report=ylt-cov-report
+ fi
+ llvm-cov show $(find . -maxdepth 1 -type f -executable | awk '{print "-object " $0}' | xargs) -instr-profile=test_ylt.profdata -format=html -output-dir=$report -ignore-filename-regex='thirdparty|src|template_switch|concurrentqueue|dragonbox_to_chars|dragonbox|expected' -show-instantiations=false
+ echo "path=build/output/tests/$report" >> $GITHUB_OUTPUT
+ cov_data=$(grep -w '
Totals
' $report/index.html | awk -F 'Totals' '{print $NF}' | cut -d ')' -f 2 | awk -F '>' '{print $NF}' | awk -F '%' '{print $1}')
+ echo "coverage data: $cov_data"
+ echo "report=$report" >> $GITHUB_OUTPUT
+ echo "data=$cov_data" >> $GITHUB_OUTPUT
+ shell: bash
+
+ - name: 'Upload coverage results'
+ uses: actions/upload-artifact@v4.3.6
+ with:
+ name: ${{ steps.get-cov-report.outputs.report }}
+ path: ${{ steps.get-cov-report.outputs.path }}
+
+ - name: 'Checkout source code'
+ uses: actions/checkout@v4
+ if: ${{ inputs.reset-commit-id }} != ""
diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml
index 0f9cd2973..4c3abfe43 100644
--- a/.github/workflows/clang-format.yml
+++ b/.github/workflows/clang-format.yml
@@ -14,7 +14,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- name: install clang-format
diff --git a/.github/workflows/clean_cache.yml b/.github/workflows/clean_cache.yml
index 344c2e61e..243ad816f 100644
--- a/.github/workflows/clean_cache.yml
+++ b/.github/workflows/clean_cache.yml
@@ -16,7 +16,7 @@ jobs:
contents: read
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Cleanup
run: |
diff --git a/.github/workflows/comment.yml b/.github/workflows/comment.yml
new file mode 100644
index 000000000..b886d94b8
--- /dev/null
+++ b/.github/workflows/comment.yml
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2024 Alibaba Group Holding Limited. All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Alibaba designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+name: Cov Report Comment
+
+on:
+ workflow_run:
+ workflows: ["Ubuntu 22.04 (llvm cov)"]
+ types:
+ - completed
+
+jobs:
+ comment:
+ runs-on: ubuntu-22.04
+ permissions: write-all
+ steps:
+ - name: 'Download artifact'
+ uses: actions/github-script@v6
+ with:
+ script: |
+ let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ run_id: context.payload.workflow_run.id,
+ });
+ let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
+ return artifact.name == "action_msg"
+ })[0];
+ let download = await github.rest.actions.downloadArtifact({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ artifact_id: matchArtifact.id,
+ archive_format: 'zip',
+ });
+ let fs = require('fs');
+ fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/action_msg.zip`, Buffer.from(download.data));
+ - name: 'Comment'
+ run: |
+ unzip action_msg.zip
+ pr_id=`grep 'pr_id' action_msg | cut -d '=' -f 2`
+ action_id=`grep 'action_id' action_msg | cut -d '=' -f 2`
+ content=$(echo "for detail, [goto summary](https://github.com/${{ github.repository_owner }}/${{ github.event.repository.name }}/actions/runs/${action_id}) download Artifacts \`base-ylt-cov-report\`(base commit coverage report) and \`ylt-cov-report\`(current pull request coverage report)")
+ curl -L -X POST "https://api.github.com/repos/${{github.repository}}/issues/${pr_id}/comments" -H "Authorization: Bearer ${{github.token}}" -H 'Content-Type: application/json' -d "{\"body\": \"$content\"}"
+ shell: bash
diff --git a/.github/workflows/linux_llvm_cov.yml b/.github/workflows/linux_llvm_cov.yml
index 08cc89cc2..82429e389 100644
--- a/.github/workflows/linux_llvm_cov.yml
+++ b/.github/workflows/linux_llvm_cov.yml
@@ -1,70 +1,108 @@
+#
+# Copyright (c) 2024 Alibaba Group Holding Limited. All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Alibaba designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
name: Ubuntu 22.04 (llvm cov)
on:
- pull_request_target:
+ pull_request:
branches:
- main
- fix_coverage_show
+ - 0.3.8.2
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
jobs:
- build:
+ prerequisites:
runs-on: ubuntu-22.04
-
+ permissions: write-all
+ outputs:
+ id: ${{ steps.get-base-commit.outputs.id }}
steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - name: Install Dependencies
+ - name: 'Get Base Commit id'
+ id: get-base-commit
run: |
- sudo apt-get install openssl
- sudo apt-get install libssl-dev
- sudo apt-get install llvm
-
- - name: Install newer Clang
+ sudo apt install -y jq
+ base_commit_id=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }} | jq -r .base.sha)
+ echo "::set-output name=id::$base_commit_id"
+ shell: bash
+ - name: 'Store Message'
run: |
- sudo rm /etc/apt/sources.list.d/microsoft-prod.list
- sudo apt-get update
- wget https://apt.llvm.org/llvm.sh
- chmod +x ./llvm.sh
- sudo ./llvm.sh 17
+ mkdir -p ./msg
+ echo "action_id=${{github.run_id}}" >> ./msg/action_msg
+ echo "pr_id=${{github.event.pull_request.number}}" >> ./msg/action_msg
+ shell: bash
+ - name: 'Upload Action Message'
+ uses: actions/upload-artifact@v4
+ with:
+ name: action_msg
+ path: msg/
- - name: Run Coverage
- run: |
- ls
- cp -r src/coro_rpc/tests/openssl_files .
- ls
- mkdir build && cd build
- CC=clang-17 CXX=clang++-17 cmake .. -DCOVERAGE_TEST=ON -DYLT_ENABLE_SSL=ON
- make -j
- export LLVM_PROFILE_FILE="test_ylt-%m.profraw"
- cd output
- cd tests
- ./coro_io_test
- ./coro_rpc_test
- ./easylog_test
- ./struct_pack_test
- ./struct_pack_test_with_optimize
- llvm-profdata merge -sparse test_ylt-*.profraw -o test_ylt.profdata
- llvm-cov show coro_io_test -object coro_rpc_test -object easylog_test -object struct_pack_test -object struct_pack_test_with_optimize -instr-profile=test_ylt.profdata -format=html -output-dir=../../.coverage_llvm_cov -ignore-filename-regex="thirdparty|asio|src" -show-instantiations=false
- echo "Done!"
+ base-cov-test:
+ needs: prerequisites
+ runs-on: ubuntu-22.04
+ outputs:
+ data: ${{ steps.base-cov.outputs.data }}
+ steps:
+ - name: 'Checkout source code'
+ uses: actions/checkout@v4
+ - name: 'Base coverage test'
+ id: base-cov
+ uses: ./.github/actions/coverage
+ with:
+ reset-commit-id: ${{ needs.prerequisites.outputs.id }}
- - name: Upload Coverage Results
- uses: actions/upload-artifact@v3
+ cov-test:
+ needs: prerequisites
+ runs-on: ubuntu-22.04
+ outputs:
+ data: ${{ steps.cov.outputs.data }}
+ steps:
+ - name: 'Checkout source code'
+ uses: actions/checkout@v4
+ - name: 'Coverage test'
+ id: cov
+ uses: ./.github/actions/coverage
with:
- name: llvm-cov
- path: ${{ github.workspace }}/build/.coverage_llvm_cov
+ reset-commit-id: ""
- - name: Create Code Coverage Report
- working-directory: ${{github.workspace}}/build/output/tests
+ compare-cov-data:
+ needs:
+ - base-cov-test
+ - cov-test
+ runs-on: ubuntu-22.04
+ steps:
+ - name: 'Compare data'
run: |
- echo "Code Coverage Report" > tmp.log
- echo "for detail, [goto summary](https://github.com/${{ github.repository_owner }}/${{ github.event.repository.name }}/actions/runs/${{github.run_id}}) download Artifacts `llvm-cov`" >> tmp.log
- echo "\`\`\`" >> tmp.log
- llvm-cov report coro_io_test -object coro_rpc_test -object easylog_test -object struct_pack_test -object struct_pack_test_with_optimize -instr-profile=test_ylt.profdata -ignore-filename-regex="thirdparty|asio|src" -show-region-summary=false >> tmp.log
- echo "\`\`\`" >> tmp.log
-
- - name: Create Comment
- uses: peter-evans/create-or-update-comment@v2
- with:
- issue-number: ${{ github.event.pull_request.number }}
- body-file: '${{github.workspace}}/build/output/tests/tmp.log'
+ sudo apt install -y bc
+ result=$(echo "${{ needs.cov-test.outputs.data }} > 70" | bc)
+ if [ "$result" -ne 1 ];then
+ echo "coverage cannot be lower than 70%!"
+ exit 1
+ fi
+ result=$(echo "${{ needs.cov-test.outputs.data }} > $(echo "${{ needs.base-cov-test.outputs.data}} * 0.97" | bc)" | bc)
+ if [ "$result" -ne 1 ];then
+ echo "coverage has decreased over 3%!"
+ exit 1
+ fi
+ shell: bash
diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml
index 790178fc0..08e3242b7 100644
--- a/.github/workflows/mac.yml
+++ b/.github/workflows/mac.yml
@@ -14,11 +14,11 @@ jobs:
mode: [ Debug ] #mode: [Release, Debug]
ssl: [ ON, OFF ]
- runs-on: macos-12
+ runs-on: macos-latest
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
# - name: SetUp HomeBrew
# id: set-up-homebrew
diff --git a/.github/workflows/s390x.yml b/.github/workflows/s390x.yml
index 613aaee9e..2fd459c54 100644
--- a/.github/workflows/s390x.yml
+++ b/.github/workflows/s390x.yml
@@ -12,7 +12,7 @@ jobs:
name: Build Linux on s390x arch and run unit tests
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2
name: Test
id: runcmd
diff --git a/.github/workflows/ubuntu_clang.yml b/.github/workflows/ubuntu_clang.yml
index 48fdd379f..13f2e79ec 100644
--- a/.github/workflows/ubuntu_clang.yml
+++ b/.github/workflows/ubuntu_clang.yml
@@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install Dependencies
run: sudo apt-get install openssl libssl-dev
@@ -67,7 +67,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install Dependencies
run: |
@@ -117,7 +117,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install liburing
run: sudo apt-get install liburing-dev
@@ -164,7 +164,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install ninja-build tool
uses: seanmiddleditch/gha-setup-ninja@master
diff --git a/.github/workflows/ubuntu_gcc.yml b/.github/workflows/ubuntu_gcc.yml
index d022a32f1..e83f41339 100644
--- a/.github/workflows/ubuntu_gcc.yml
+++ b/.github/workflows/ubuntu_gcc.yml
@@ -21,7 +21,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install Dependencies
run: sudo apt-get install openssl libssl-dev
@@ -57,7 +57,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install Dependencies
run: |
@@ -98,7 +98,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install liburing
run: sudo apt-get install liburing-dev
@@ -135,7 +135,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install ninja-build tool
uses: seanmiddleditch/gha-setup-ninja@master
diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml
index 4ead005d2..8a1af92ea 100644
--- a/.github/workflows/website.yml
+++ b/.github/workflows/website.yml
@@ -33,7 +33,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v3
- name: Install package
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index 08d37b547..2b6a52037 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -22,7 +22,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Enable Developer Command Prompt
uses: ilammy/msvc-dev-cmd@v1.12.0
with:
@@ -56,7 +56,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Enable Developer Command Prompt
uses: ilammy/msvc-dev-cmd@v1.12.0
with:
diff --git a/include/ylt/coro_http/coro_http_client.hpp b/include/ylt/coro_http/coro_http_client.hpp
index e6fc026fd..d9ceee2ca 100644
--- a/include/ylt/coro_http/coro_http_client.hpp
+++ b/include/ylt/coro_http/coro_http_client.hpp
@@ -15,14 +15,26 @@
*/
#pragma once
#ifdef YLT_ENABLE_SSL
+#ifndef CINATRA_ENABLE_SSL
#define CINATRA_ENABLE_SSL
#endif
+#endif
#include
+#ifndef CINATRA_LOG_ERROR
#define CINATRA_LOG_ERROR ELOG_ERROR
+#endif
+#ifndef CINATRA_LOG_WARNING
#define CINATRA_LOG_WARNING ELOG_WARN
+#endif
+#ifndef CINATRA_LOG_INFO
#define CINATRA_LOG_INFO ELOG_INFO
+#endif
+#ifndef CINATRA_LOG_DEBUG
#define CINATRA_LOG_DEBUG ELOG_DEBUG
+#endif
+#ifndef CINATRA_LOG_TRACE
#define CINATRA_LOG_TRACE ELOG_TRACE
+#endif
#include
diff --git a/include/ylt/coro_http/coro_http_server.hpp b/include/ylt/coro_http/coro_http_server.hpp
index a4bb1ecf4..16ee9059f 100644
--- a/include/ylt/coro_http/coro_http_server.hpp
+++ b/include/ylt/coro_http/coro_http_server.hpp
@@ -15,14 +15,26 @@
*/
#pragma once
#ifdef YLT_ENABLE_SSL
+#ifndef CINATRA_ENABLE_SSL
#define CINATRA_ENABLE_SSL
#endif
+#endif
#include
+#ifndef CINATRA_LOG_ERROR
#define CINATRA_LOG_ERROR ELOG_ERROR
+#endif
+#ifndef CINATRA_LOG_WARNING
#define CINATRA_LOG_WARNING ELOG_WARN
+#endif
+#ifndef CINATRA_LOG_INFO
#define CINATRA_LOG_INFO ELOG_INFO
+#endif
+#ifndef CINATRA_LOG_DEBUG
#define CINATRA_LOG_DEBUG ELOG_DEBUG
+#endif
+#ifndef CINATRA_LOG_TRACE
#define CINATRA_LOG_TRACE ELOG_TRACE
+#endif
#include
diff --git a/include/ylt/coro_rpc/impl/common_service.hpp b/include/ylt/coro_rpc/impl/common_service.hpp
index c081232ed..af8bf6a89 100644
--- a/include/ylt/coro_rpc/impl/common_service.hpp
+++ b/include/ylt/coro_rpc/impl/common_service.hpp
@@ -80,36 +80,36 @@ inline bool init_ssl_context_helper(asio::ssl::context &context,
auto key_file = fs::path(conf.base_path).append(conf.key_file);
auto dh_file = fs::path(conf.base_path).append(conf.dh_file);
- ELOGV(INFO, "current path %s", fs::current_path().string().data());
+ ELOG_INFO << "current path " << fs::current_path().string();
if (file_exists(cert_file)) {
- ELOGV(INFO, "load %s", cert_file.string().data());
+ ELOG_INFO << "load " << cert_file.string();
context.use_certificate_chain_file(cert_file);
}
else {
- ELOGV(ERROR, "no certificate file %s", cert_file.string().data());
+ ELOG_ERROR << "no certificate file " << cert_file.string();
return false;
}
if (file_exists(key_file)) {
- ELOGV(INFO, "load %s", key_file.string().data());
+ ELOG_INFO << "load " << key_file.string();
context.use_private_key_file(key_file, asio::ssl::context::pem);
}
else {
- ELOGV(ERROR, "no private key file %s", key_file.string().data());
+ ELOG_ERROR << "no private file " << key_file.string();
return false;
}
if (file_exists(dh_file)) {
- ELOGV(INFO, "load %s", dh_file.string().data());
+ ELOG_INFO << "load " << dh_file.string();
context.use_tmp_dh_file(dh_file);
}
else {
- ELOGV(INFO, "no temp dh file %s", dh_file.string().data());
+ ELOG_INFO << "no temp dh file " << dh_file.string();
}
return true;
} catch (std::exception &e) {
- ELOGV(INFO, "%s", e.what());
+ ELOG_INFO << e.what();
return false;
}
}
diff --git a/include/ylt/coro_rpc/impl/context.hpp b/include/ylt/coro_rpc/impl/context.hpp
index cdeb8d0ba..aeef8bb78 100644
--- a/include/ylt/coro_rpc/impl/context.hpp
+++ b/include/ylt/coro_rpc/impl/context.hpp
@@ -47,13 +47,13 @@ class context_base {
auto old_flag = self_->status_.exchange(context_status::start_response);
if (old_flag != context_status::init)
AS_UNLIKELY {
- ELOGV(ERROR, "response message more than one time");
+ ELOG_ERROR << "response message more than one time";
return false;
}
if (self_->has_closed())
AS_UNLIKELY {
- ELOGV(DEBUG, "response_msg failed: connection has been closed");
+ ELOG_DEBUG << "response_msg failed: connection has been closed";
return false;
}
return true;
diff --git a/include/ylt/coro_rpc/impl/coro_connection.hpp b/include/ylt/coro_rpc/impl/coro_connection.hpp
index b1e590392..be52bc77c 100644
--- a/include/ylt/coro_rpc/impl/coro_connection.hpp
+++ b/include/ylt/coro_rpc/impl/coro_connection.hpp
@@ -146,8 +146,8 @@ class coro_connection : public std::enable_shared_from_this {
~coro_connection() {
if (!has_closed_) {
#ifdef UNIT_TEST_INJECT
- ELOGV(INFO, "~async_connection conn_id %d, client_id %d", conn_id_,
- client_id_);
+ ELOG_INFO << "~async_connection conn_id " << conn_id_ << ", client_id "
+ << client_id_;
#endif
close();
}
@@ -167,18 +167,18 @@ class coro_connection : public std::enable_shared_from_this {
#ifdef YLT_ENABLE_SSL
if (use_ssl_) {
assert(ssl_stream_);
- ELOGV(INFO, "begin to handshake conn_id %d", conn_id_);
+ ELOG_INFO << "begin to handshake conn_id " << conn_id_;
reset_timer();
auto shake_ec = co_await coro_io::async_handshake(
ssl_stream_, asio::ssl::stream_base::server);
cancel_timer();
if (shake_ec) {
- ELOGV(ERROR, "handshake failed: %s conn_id %d",
- shake_ec.message().data(), conn_id_);
+ ELOG_ERROR << "handshake failed: " << shake_ec.message() << " conn_id "
+ << conn_id_;
close();
}
else {
- ELOGV(INFO, "handshake ok conn_id %d", conn_id_);
+ ELOG_INFO << "handshake ok conn_id " << conn_id_;
co_await start_impl(router, *ssl_stream_);
}
}
@@ -204,22 +204,20 @@ class coro_connection : public std::enable_shared_from_this {
// less than RPC_HEAD_LEN. Incomplete data will be discarded.
// So, no special handling of eof is required.
if (ec) {
- ELOGV(INFO, "connection %d close: %s", conn_id_, ec.message().data());
+ ELOG_INFO << "connection " << conn_id_ << " close: " << ec.message();
close();
break;
}
#ifdef UNIT_TEST_INJECT
client_id_ = req_head_tmp.seq_num;
- ELOGV(INFO, "conn_id %d, client_id %d", conn_id_, client_id_);
+ ELOG_INFO << "conn_id " << conn_id_ << " client_id " << client_id_;
#endif
#ifdef UNIT_TEST_INJECT
if (g_action == inject_action::close_socket_after_read_header) {
- ELOGV(WARN,
- "inject action: close_socket_after_read_header, conn_id %d, "
- "client_id %d",
- conn_id_, client_id_);
+ ELOG_WARN << "inject action: close_socket_after_read_header, conn_id "
+ << conn_id_ << ", client_id " << client_id_;
close();
break;
}
@@ -250,7 +248,7 @@ class coro_connection : public std::enable_shared_from_this {
if (!serialize_proto.has_value())
AS_UNLIKELY {
- ELOGV(ERROR, "bad serialize protocol type, conn_id %d", conn_id_);
+ ELOG_ERROR << "bad serialize protocol type, conn_id " << conn_id_;
close();
break;
}
@@ -265,8 +263,8 @@ class coro_connection : public std::enable_shared_from_this {
if (ec)
AS_UNLIKELY {
- ELOGV(ERROR, "read error: %s, conn_id %d", ec.message().data(),
- conn_id_);
+ ELOG_ERROR << "read error: " << ec.message() << ", conn_id "
+ << conn_id_;
close();
break;
}
@@ -317,8 +315,9 @@ class coro_connection : public std::enable_shared_from_this {
}
#ifdef UNIT_TEST_INJECT
if (g_action == inject_action::close_socket_after_send_length) {
- ELOGV(WARN, "inject action: close_socket_after_send_length", conn_id_,
- client_id_);
+ ELOG_WARN
+ << "inject action: close_socket_after_send_length , conn_id "
+ << conn_id_ << ", client_id " << client_id_;
std::string header_buf = rpc_protocol::prepare_response(
resp_buf, req_head, 0, resp_err, "");
co_await coro_io::async_write(socket, asio::buffer(header_buf));
@@ -326,11 +325,8 @@ class coro_connection : public std::enable_shared_from_this {
break;
}
if (g_action == inject_action::server_send_bad_rpc_result) {
- ELOGV(
- WARN,
- "inject action: server_send_bad_rpc_result conn_id %d, client_id "
- "%d",
- conn_id_, client_id_);
+ ELOG_WARN << "inject action: server_send_bad_rpc_result , conn_id "
+ << conn_id_ << ", client_id " << client_id_;
resp_buf[0] = resp_buf[0] + 1;
}
#endif
@@ -362,8 +358,7 @@ class coro_connection : public std::enable_shared_from_this {
if (resp_err) {
resp_error_msg = std::move(resp_buf);
resp_buf = {};
- ELOGV(WARNING, "rpc route/execute error, error msg: %s",
- resp_error_msg.data());
+ ELOG_WARN << "rpc route/execute error, error msg: " << resp_error_msg;
}
std::string header_buf = rpc_protocol::prepare_response(
resp_buf, req_head, attachment().length(), resp_err, resp_error_msg);
@@ -460,12 +455,12 @@ class coro_connection : public std::enable_shared_from_this {
rpc_conn self) noexcept {
if (has_closed())
AS_UNLIKELY {
- ELOGV(DEBUG, "response_msg failed: connection has been closed");
+ ELOG_DEBUG << "response_msg failed: connection has been closed";
co_return;
}
#ifdef UNIT_TEST_INJECT
if (g_action == inject_action::close_socket_after_send_length) {
- ELOGV(WARN, "inject action: close_socket_after_send_length");
+ ELOG_WARN << "inject action: close_socket_after_send_length";
body_buf.clear();
}
#endif
@@ -488,11 +483,9 @@ class coro_connection : public std::enable_shared_from_this {
auto &msg = write_queue_.front();
#ifdef UNIT_TEST_INJECT
if (g_action == inject_action::force_inject_connection_close_socket) {
- ELOGV(
- WARN,
- "inject action: force_inject_connection_close_socket, conn_id %d, "
- "client_id %d",
- conn_id_, client_id_);
+ ELOG_WARN
+ << "inject action: force_inject_connection_close_socket , conn_id "
+ << conn_id_ << ", client_id " << client_id_;
close();
co_return;
}
@@ -535,8 +528,8 @@ class coro_connection : public std::enable_shared_from_this {
}
if (ret.first)
AS_UNLIKELY {
- ELOGV(ERROR, "%s, %s", ret.first.message().data(),
- "async_write error");
+ ELOG_ERROR << ret.first.message() << ", "
+ << "async_write error";
close();
co_return;
}
@@ -544,10 +537,8 @@ class coro_connection : public std::enable_shared_from_this {
}
#ifdef UNIT_TEST_INJECT
if (g_action == inject_action::close_socket_after_send_length) {
- ELOGV(INFO,
- "inject action: close_socket_after_send_length, conn_id %d, "
- "client_id %d",
- conn_id_, client_id_);
+ ELOG_INFO << "inject action: close_socket_after_send_length , conn_id "
+ << conn_id_ << ", client_id " << client_id_;
// Attention: close ssl stream after read error
// otherwise, server will crash
close();
@@ -557,7 +548,7 @@ class coro_connection : public std::enable_shared_from_this {
}
void close() {
- ELOGV(TRACE, "connection closed");
+ ELOG_TRACE << "connection closed";
if (has_closed_) {
return;
}
@@ -580,10 +571,10 @@ class coro_connection : public std::enable_shared_from_this {
[this, self = shared_from_this()](asio::error_code const &ec) {
if (!ec) {
#ifdef UNIT_TEST_INJECT
- ELOGV(INFO, "close timeout client_id %d conn_id %d", client_id_,
- conn_id_);
+ ELOG_INFO << "close timeout client client_id " << client_id_
+ << ", conn_id " << conn_id_;
#else
- ELOGV(INFO, "close timeout client conn_id %d", conn_id_);
+ ELOG_INFO << "close timeout client conn_id " << conn_id_;
#endif
close();
diff --git a/include/ylt/coro_rpc/impl/coro_rpc_client.hpp b/include/ylt/coro_rpc/impl/coro_rpc_client.hpp
index e84b09f6c..8ce0e8335 100644
--- a/include/ylt/coro_rpc/impl/coro_rpc_client.hpp
+++ b/include/ylt/coro_rpc/impl/coro_rpc_client.hpp
@@ -161,14 +161,14 @@ class coro_rpc_client {
"client has been closed"};
struct config {
uint64_t client_id = get_global_client_id();
- std::chrono::milliseconds timeout_duration =
- std::chrono::milliseconds{30000};
- std::string host;
- std::string port;
+ std::optional connect_timeout_duration;
+ std::optional request_timeout_duration;
+ std::string host{};
+ std::string port{};
bool enable_tcp_no_delay = true;
#ifdef YLT_ENABLE_SSL
- std::filesystem::path ssl_cert_path;
- std::string ssl_domain;
+ std::filesystem::path ssl_cert_path{};
+ std::string ssl_domain{};
#endif
};
@@ -203,6 +203,8 @@ class coro_rpc_client {
const config &get_config() const { return config_; }
+ config &get_config() { return config_; }
+
[[nodiscard]] bool init_config(const config &conf) {
config_ = conf;
#ifdef YLT_ENABLE_SSL
@@ -228,12 +230,12 @@ class coro_rpc_client {
*
* @param host server address
* @param port server port
- * @param timeout_duration RPC call timeout
+ * @param connect_timeout_duration RPC call timeout seconds
* @return error code
*/
[[nodiscard]] async_simple::coro::Lazy connect(
std::string host, std::string port,
- std::chrono::steady_clock::duration timeout_duration =
+ std::chrono::steady_clock::duration connect_timeout_duration =
std::chrono::seconds(30)) {
auto lock_ok = connect_mutex_.tryLock();
if (!lock_ok) {
@@ -241,44 +243,32 @@ class coro_rpc_client {
co_return err_code{};
// do nothing, someone has reconnect the client
}
- config_.host = std::move(host);
- config_.port = std::move(port);
- config_.timeout_duration =
- std::chrono::duration_cast(timeout_duration);
+
+ if (config_.host.empty()) {
+ config_.host = std::move(host);
+ }
+ if (config_.port.empty()) {
+ config_.port = std::move(port);
+ }
+ if (!config_.connect_timeout_duration) {
+ config_.connect_timeout_duration =
+ std::chrono::duration_cast(
+ connect_timeout_duration);
+ }
+
auto ret = co_await connect_impl();
connect_mutex_.unlock();
co_return std::move(ret);
}
[[nodiscard]] async_simple::coro::Lazy connect(
std::string_view endpoint,
- std::chrono::steady_clock::duration timeout_duration =
+ std::chrono::steady_clock::duration connect_timeout_duration =
std::chrono::seconds(30)) {
auto pos = endpoint.find(':');
- auto lock_ok = connect_mutex_.tryLock();
- if (!lock_ok) {
- co_await connect_mutex_.coScopedLock();
- co_return err_code{};
- // do nothing, someone has reconnect the client
- }
- config_.host = endpoint.substr(0, pos);
- config_.port = endpoint.substr(pos + 1);
- config_.timeout_duration =
- std::chrono::duration_cast(timeout_duration);
- auto ret = co_await connect_impl();
- connect_mutex_.unlock();
- co_return std::move(ret);
- }
+ std::string host(endpoint.substr(0, pos));
+ std::string port(endpoint.substr(pos + 1));
- [[nodiscard]] async_simple::coro::Lazy connect() {
- auto lock_ok = connect_mutex_.tryLock();
- if (!lock_ok) {
- co_await connect_mutex_.coScopedLock();
- co_return err_code{};
- // do nothing, someone has reconnect the client
- }
- auto ret = co_await connect_impl();
- connect_mutex_.unlock();
- co_return std::move(ret);
+ return connect(std::move(host), std::move(port), connect_timeout_duration);
}
#ifdef YLT_ENABLE_SSL
@@ -323,11 +313,12 @@ class coro_rpc_client {
*/
template
async_simple::coro::Lazy())>>
- call_for(auto duration, Args &&...args) {
+ call_for(auto request_timeout_duration, Args &&...args) {
using return_type = decltype(get_return_type());
auto async_result =
co_await co_await send_request_for_with_attachment(
- duration, req_attachment_, std::forward(args)...);
+ request_timeout_duration, req_attachment_,
+ std::forward(args)...);
req_attachment_ = {};
if (async_result) {
control_->resp_buffer_ = async_result->release_buffer();
@@ -353,13 +344,13 @@ class coro_rpc_client {
uint32_t get_client_id() const { return config_.client_id; }
void close() {
- // ELOGV(INFO, "client_id %d close", config_.client_id);
+ // ELOG_INFO << "client_id " << config_.client_id << " close";
close_socket(control_);
}
bool set_req_attachment(std::string_view attachment) {
if (attachment.size() > UINT32_MAX) {
- ELOGV(ERROR, "too large rpc attachment");
+ ELOG_ERROR << "too large rpc attachment";
return false;
}
req_attachment_ = attachment;
@@ -408,11 +399,14 @@ class coro_rpc_client {
#endif
control_->has_closed_ = false;
- ELOGV(INFO, "client_id %d begin to connect %s", config_.client_id,
- config_.port.data());
- timeout(*this->timer_, config_.timeout_duration, "connect timer canceled")
- .start([](auto &&) {
- });
+ ELOG_INFO << "client_id " << config_.client_id << " begin to connect "
+ << config_.port;
+ auto conn_timeout_dur = *config_.connect_timeout_duration;
+ if (conn_timeout_dur.count() >= 0) {
+ timeout(*this->timer_, conn_timeout_dur, "connect timer canceled")
+ .start([](auto &&) {
+ });
+ }
std::error_code ec = co_await coro_io::async_connect(
&control_->executor_, control_->socket_, config_.host, config_.port);
@@ -427,7 +421,7 @@ class coro_rpc_client {
}
if (control_->is_timeout_) {
- ELOGV(WARN, "client_id %d connect timeout", config_.client_id);
+ ELOG_WARN << "client_id " << config_.client_id << " connect timeout";
co_return errc::timed_out;
}
if (config_.enable_tcp_no_delay == true) {
@@ -440,8 +434,8 @@ class coro_rpc_client {
auto shake_ec = co_await coro_io::async_handshake(
control_->ssl_stream_, asio::ssl::stream_base::client);
if (shake_ec) {
- ELOGV(WARN, "client_id %d handshake failed: %s", config_.client_id,
- shake_ec.message().data());
+ ELOG_WARN << "client_id " << config_.client_id
+ << " handshake failed: " << shake_ec.message();
co_return errc::not_connected;
}
}
@@ -453,16 +447,15 @@ class coro_rpc_client {
[[nodiscard]] bool init_ssl_impl() {
try {
ssl_init_ret_ = false;
- ELOGV(INFO, "init ssl: %s", config_.ssl_domain.data());
+ ELOG_INFO << "init ssl: " << config_.ssl_domain;
auto &cert_file = config_.ssl_cert_path;
- ELOGV(INFO, "current path %s",
- std::filesystem::current_path().string().data());
+ ELOG_INFO << "current path: " << std::filesystem::current_path().string();
if (file_exists(cert_file)) {
- ELOGV(INFO, "load %s", cert_file.string().data());
+ ELOG_INFO << "load " << cert_file.string();
ssl_ctx_.load_verify_file(cert_file);
}
else {
- ELOGV(INFO, "no certificate file %s", cert_file.string().data());
+ ELOG_INFO << "no certificate file " << cert_file.string();
return ssl_init_ret_;
}
ssl_ctx_.set_verify_mode(asio::ssl::verify_peer);
@@ -473,7 +466,7 @@ class coro_rpc_client {
control_->socket_, ssl_ctx_);
ssl_init_ret_ = true;
} catch (std::exception &e) {
- ELOGV(ERROR, "init ssl failed: %s", e.what());
+ ELOG_ERROR << "init ssl failed: " << e.what();
}
return ssl_init_ret_;
}
@@ -579,7 +572,7 @@ class coro_rpc_client {
#endif
auto sz = buffer.size() - coro_rpc_protocol::REQ_HEAD_LEN;
if (sz > UINT32_MAX) {
- ELOGV(ERROR, "too large rpc body");
+ ELOG_ERROR << "too large rpc body";
return {};
}
header.length = sz;
@@ -626,7 +619,7 @@ class coro_rpc_client {
}
has_error = true;
// deserialize failed.
- ELOGV(WARNING, "deserilaize rpc result failed");
+ ELOG_WARN << "deserilaize rpc result failed";
err = {errc::invalid_rpc_result, "failed to deserialize rpc return value"};
return rpc_result{unexpect_t{}, std::move(err)};
}
@@ -747,13 +740,13 @@ class coro_rpc_client {
private:
template
async_simple::coro::Lazy send_request_for_impl(
- auto duration, uint32_t &id, coro_io::period_timer &timer,
+ auto request_timeout_duration, uint32_t &id, coro_io::period_timer &timer,
std::string_view attachment, Args &&...args) {
using R = decltype(get_return_type());
if (control_->has_closed_)
AS_UNLIKELY {
- ELOGV(ERROR, "client has been closed, please re-connect");
+ ELOG_ERROR << "client has been closed, please re-connect";
co_return rpc_error{errc::io_error,
"client has been closed, please re-connect"};
}
@@ -766,9 +759,10 @@ class coro_rpc_client {
static_check();
- if (duration.count() > 0) {
- timeout(timer, duration, "rpc call timer canceled").start([](auto &&) {
- });
+ if (request_timeout_duration.count() >= 0) {
+ timeout(timer, request_timeout_duration, "rpc call timer canceled")
+ .start([](auto &&) {
+ });
}
#ifdef YLT_ENABLE_SSL
@@ -965,16 +959,20 @@ class coro_rpc_client {
template
async_simple::coro::Lazy())>>>
- send_request_for_with_attachment(auto time_out_duration,
+ send_request_for_with_attachment(auto request_timeout_duration,
std::string_view request_attachment,
Args &&...args) {
using rpc_return_t = decltype(get_return_type());
recving_guard guard(control_.get());
uint32_t id;
+ if (!config_.request_timeout_duration) {
+ config_.request_timeout_duration = request_timeout_duration;
+ }
+
auto timer = std::make_unique(
control_->executor_.get_asio_executor());
auto result = co_await send_request_for_impl(
- time_out_duration, id, *timer, request_attachment,
+ *config_.request_timeout_duration, id, *timer, request_attachment,
std::forward(args)...);
auto &control = *control_;
if (!result) {
@@ -1041,7 +1039,7 @@ class coro_rpc_client {
if (g_action == inject_action::client_close_socket_after_send_header) {
ret = co_await coro_io::async_write(
socket, asio::buffer(buffer.data(), coro_rpc_protocol::REQ_HEAD_LEN));
- ELOGV(INFO, "client_id %d close socket", config_.client_id);
+ ELOG_INFO << "client_id " << config_.client_id << " close socket";
close();
co_return rpc_error{errc::io_error, ret.first.message()};
}
@@ -1050,7 +1048,7 @@ class coro_rpc_client {
ret = co_await coro_io::async_write(
socket,
asio::buffer(buffer.data(), coro_rpc_protocol::REQ_HEAD_LEN - 1));
- ELOGV(INFO, "client_id %d close socket", config_.client_id);
+ ELOG_INFO << "client_id " << config_.client_id << " close socket";
close();
co_return rpc_error{errc::io_error, ret.first.message()};
}
@@ -1058,7 +1056,7 @@ class coro_rpc_client {
inject_action::client_shutdown_socket_after_send_header) {
ret = co_await coro_io::async_write(
socket, asio::buffer(buffer.data(), coro_rpc_protocol::REQ_HEAD_LEN));
- ELOGV(INFO, "client_id %d shutdown", config_.client_id);
+ ELOG_INFO << "client_id " << config_.client_id << " shutdown";
control_->socket_.shutdown(asio::ip::tcp::socket::shutdown_send);
co_return rpc_error{errc::io_error, ret.first.message()};
}
@@ -1106,8 +1104,8 @@ class coro_rpc_client {
#endif
#ifdef UNIT_TEST_INJECT
if (g_action == inject_action::client_close_socket_after_send_payload) {
- ELOGV(INFO, "client_id %d client_close_socket_after_send_payload",
- config_.client_id);
+ ELOG_INFO << "client_id " << config_.client_id
+ << " client_close_socket_after_send_payload";
close();
co_return rpc_error{errc::io_error, ret.first.message()};
}
diff --git a/include/ylt/coro_rpc/impl/coro_rpc_server.hpp b/include/ylt/coro_rpc/impl/coro_rpc_server.hpp
index 3b59f6957..d38a57c92 100644
--- a/include/ylt/coro_rpc/impl/coro_rpc_server.hpp
+++ b/include/ylt/coro_rpc/impl/coro_rpc_server.hpp
@@ -118,7 +118,7 @@ class coro_rpc_server_base {
}
~coro_rpc_server_base() {
- ELOGV(INFO, "coro_rpc_server will quit");
+ ELOG_INFO << "coro_rpc_server will quit";
stop();
}
@@ -153,10 +153,10 @@ class coro_rpc_server_base {
std::unique_lock lock(start_mtx_);
if (flag_ != stat::init) {
if (flag_ == stat::started) {
- ELOGV(INFO, "start again");
+ ELOG_INFO << "start again";
}
else if (flag_ == stat::stop) {
- ELOGV(INFO, "has stoped");
+ ELOG_INFO << "has stoped";
}
return make_error_future(
coro_rpc::err_code{coro_rpc::errc::server_has_ran});
@@ -206,7 +206,7 @@ class coro_rpc_server_base {
return;
}
- ELOGV(INFO, "begin to stop coro_rpc_server, conn size %d", conns_.size());
+ ELOG_INFO << "begin to stop coro_rpc_server, conn size " << conns_.size();
if (flag_ == stat::started) {
close_acceptor();
@@ -221,15 +221,15 @@ class coro_rpc_server_base {
conns_.clear();
}
- ELOGV(INFO, "wait for server's thread-pool finish all work.");
+ ELOG_INFO << "wait for server's thread-pool finish all work.";
pool_.stop();
- ELOGV(INFO, "server's thread-pool finished.");
+ ELOG_INFO << "server's thread-pool finished.";
}
if (thd_.joinable()) {
thd_.join();
}
- ELOGV(INFO, "stop coro_rpc_server ok");
+ ELOG_INFO << "stop coro_rpc_server ok.";
flag_ = stat::stop;
}
@@ -319,7 +319,7 @@ class coro_rpc_server_base {
private:
coro_rpc::err_code listen() {
- ELOGV(INFO, "begin to listen");
+ ELOG_INFO << "begin to listen";
using asio::ip::tcp;
asio::error_code ec;
asio::ip::tcp::resolver::query query(address_, std::to_string(port_));
@@ -328,15 +328,15 @@ class coro_rpc_server_base {
asio::ip::tcp::resolver::iterator it_end;
if (ec || it == it_end) {
- ELOGV(ERROR, "resolve address %s error : %s", address_.data(),
- ec.message().data());
+ ELOG_ERROR << "resolve address " << address_
+ << " error: " << ec.message();
return coro_rpc::errc::bad_address;
}
auto endpoint = it->endpoint();
acceptor_.open(endpoint.protocol(), ec);
if (ec) {
- ELOGV(ERROR, "open failed, error : %s", ec.message().data());
+ ELOG_ERROR << "open failed, error: " << ec.message();
return coro_rpc::errc::open_error;
}
#ifdef __GNUC__
@@ -344,8 +344,7 @@ class coro_rpc_server_base {
#endif
acceptor_.bind(endpoint, ec);
if (ec) {
- ELOGV(ERROR, "bind port %d error : %s", port_.load(),
- ec.message().data());
+ ELOG_ERROR << "bind port " << port_.load() << " error: " << ec.message();
acceptor_.cancel(ec);
acceptor_.close(ec);
return coro_rpc::errc::address_in_used;
@@ -355,8 +354,8 @@ class coro_rpc_server_base {
#endif
acceptor_.listen(asio::socket_base::max_listen_connections, ec);
if (ec) {
- ELOGV(ERROR, "port %d listen error : %s", port_.load(),
- ec.message().data());
+ ELOG_ERROR << "port " << port_.load()
+ << " listen error: " << ec.message();
acceptor_.cancel(ec);
acceptor_.close(ec);
return coro_rpc::errc::listen_error;
@@ -364,13 +363,13 @@ class coro_rpc_server_base {
auto end_point = acceptor_.local_endpoint(ec);
if (ec) {
- ELOGV(ERROR, "get local endpoint port %d error : %s", port_.load(),
- ec.message().data());
+ ELOG_ERROR << "get local endpoint port " << port_.load()
+ << " error: " << ec.message();
return coro_rpc::errc::address_in_used;
}
port_ = end_point.port();
- ELOGV(INFO, "listen port %d successfully", port_.load());
+ ELOG_INFO << "listen port " << port_.load() << " successfully";
return {};
}
@@ -390,7 +389,7 @@ class coro_rpc_server_base {
}
#endif
if (error) {
- ELOGV(INFO, "accept failed, error: %s", error.message().data());
+ ELOG_INFO << "accept failed, error: " << error.message();
if (error == asio::error::operation_aborted ||
error == asio::error::bad_descriptor) {
acceptor_close_waiter_.set_value();
@@ -400,7 +399,7 @@ class coro_rpc_server_base {
}
int64_t conn_id = ++conn_id_;
- ELOGV(INFO, "new client conn_id %d coming", conn_id);
+ ELOG_INFO << "new client conn_id " << conn_id << " coming";
if (is_enable_tcp_no_delay_) {
socket.set_option(asio::ip::tcp::no_delay(true), error);
}
diff --git a/include/ylt/coro_rpc/impl/protocol/coro_rpc_protocol.hpp b/include/ylt/coro_rpc/impl/protocol/coro_rpc_protocol.hpp
index b74a566e3..c22fcbc80 100644
--- a/include/ylt/coro_rpc/impl/protocol/coro_rpc_protocol.hpp
+++ b/include/ylt/coro_rpc/impl/protocol/coro_rpc_protocol.hpp
@@ -145,7 +145,7 @@ struct coro_rpc_protocol {
resp_head.attach_length = attachment_len;
if (attachment_len > UINT32_MAX)
AS_UNLIKELY {
- ELOGV(ERROR, "attachment larger than 4G:%d", attachment_len);
+ ELOG_ERROR << "attachment larger than 4G: " << attachment_len;
rpc_err_code = coro_rpc::errc::message_too_large;
err_msg_buf =
"attachment larger than 4G:" + std::to_string(attachment_len) + "B";
@@ -154,7 +154,7 @@ struct coro_rpc_protocol {
else if (rpc_result.size() > UINT32_MAX)
AS_UNLIKELY {
auto sz = rpc_result.size();
- ELOGV(ERROR, "body larger than 4G:%d", sz);
+ ELOG_ERROR << "body larger than 4G: " << sz;
rpc_err_code = coro_rpc::errc::message_too_large;
err_msg_buf =
"body larger than 4G:" + std::to_string(attachment_len) + "B";
diff --git a/include/ylt/coro_rpc/impl/router.hpp b/include/ylt/coro_rpc/impl/router.hpp
index 1414b8e4e..8da6c4391 100644
--- a/include/ylt/coro_rpc/impl/router.hpp
+++ b/include/ylt/coro_rpc/impl/router.hpp
@@ -103,7 +103,7 @@ class router {
template
void regist_one_handler(Self *self) {
if (self == nullptr)
- AS_UNLIKELY { ELOGV(CRITICAL, "null connection!"); }
+ AS_UNLIKELY { ELOG_CRITICAL << "null connection!"; }
route_key key{};
@@ -128,7 +128,7 @@ class router {
template
void regist_one_handler_impl(Self *self, const route_key &key) {
if (self == nullptr)
- AS_UNLIKELY { ELOGV(CRITICAL, "null connection!"); }
+ AS_UNLIKELY { ELOG_CRITICAL << "null connection!"; }
constexpr auto name = get_func_name();
using return_type = util::function_return_type_t;
@@ -143,7 +143,7 @@ class router {
return std::visit(visitor, protocols);
});
if (!it.second) {
- ELOGV(CRITICAL, "duplication function %s register!", name.data());
+ ELOG_CRITICAL << "duplication function " << name << " registered!";
}
}
else {
@@ -161,7 +161,7 @@ class router {
protocols);
});
if (!it.second) {
- ELOGV(CRITICAL, "duplication function %s register!", name.data());
+ ELOG_CRITICAL << "duplication function " << name << " registered!";
}
}
@@ -197,7 +197,7 @@ class router {
return std::visit(visitor, protocols);
});
if (!it.second) {
- ELOGV(CRITICAL, "duplication function %s register!", name.data());
+ ELOG_CRITICAL << "duplication function " << name << " registered!";
}
}
else {
@@ -214,7 +214,7 @@ class router {
protocols);
});
if (!it.second) {
- ELOGV(CRITICAL, "duplication function %s register!", name.data());
+ ELOG_CRITICAL << "duplication function " << name << " registered!";
}
}
id2name_.emplace(key, name);
@@ -244,8 +244,7 @@ class router {
AS_LIKELY {
try {
#ifndef NDEBUG
- ELOGV(INFO, "route function name: %s", get_name(route_key).data());
-
+ ELOG_INFO << "route function name: " << get_name(route_key);
#endif
// clang-format off
co_return co_await (*handler)(data, protocols);
@@ -274,7 +273,7 @@ class router {
AS_LIKELY {
try {
#ifndef NDEBUG
- ELOGV(INFO, "route function name: %s", get_name(route_key).data());
+ ELOG_INFO << "route function name: " << get_name(route_key);
#endif
return (*handler)(data, context_info, protocols);
} catch (coro_rpc::rpc_error& err) {
diff --git a/include/ylt/metric/counter.hpp b/include/ylt/metric/counter.hpp
index d7f29e9ec..82775cd96 100644
--- a/include/ylt/metric/counter.hpp
+++ b/include/ylt/metric/counter.hpp
@@ -1,11 +1,13 @@
#pragma once
+
#include
#include
#include
-#include
+#include
+#include
#include
-#include "metric.hpp"
+#include "dynamic_metric.hpp"
#include "thread_local_value.hpp"
namespace ylt::metric {
@@ -13,97 +15,49 @@ enum class op_type_t { INC, DEC, SET };
#ifdef CINATRA_ENABLE_METRIC_JSON
struct json_counter_metric_t {
- std::map labels;
+ std::vector labels;
std::variant value;
};
YLT_REFL(json_counter_metric_t, labels, value);
struct json_counter_t {
- std::string name;
- std::string help;
- std::string type;
+ std::string_view name;
+ std::string_view help;
+ std::string_view type;
+ std::vector labels_name;
std::vector metrics;
};
-YLT_REFL(json_counter_t, name, help, type, metrics);
+YLT_REFL(json_counter_t, name, help, type, labels_name, metrics);
#endif
-template
-inline void set_value(T &label_val, value_type value, op_type_t type) {
- switch (type) {
- case op_type_t::INC: {
-#ifdef __APPLE__
- if constexpr (std::is_floating_point_v) {
- mac_os_atomic_fetch_add(&label_val, value);
- }
- else {
- label_val += value;
- }
-#else
- label_val += value;
-#endif
- } break;
- case op_type_t::DEC:
-#ifdef __APPLE__
- if constexpr (std::is_floating_point_v) {
- mac_os_atomic_fetch_sub(&label_val, value);
- }
- else {
- label_val -= value;
- }
-#else
- label_val -= value;
-#endif
- break;
- case op_type_t::SET:
- label_val = value;
- break;
- }
-}
-
template
class basic_static_counter : public static_metric {
public:
// static counter, no labels, only contains an atomic value.
basic_static_counter(std::string name, std::string help,
- size_t dupli_count = 2)
- : static_metric(MetricType::Counter, std::move(name), std::move(help)) {
- init_thread_local(dupli_count);
- }
+ uint32_t dupli_count = (std::min)(
+ 128u, std::thread::hardware_concurrency()))
+ : static_metric(MetricType::Counter, std::move(name), std::move(help)),
+ dupli_count_((std::max)(1u, dupli_count)),
+ default_label_value_(dupli_count_) {}
// static counter, contains a static labels with atomic value.
basic_static_counter(std::string name, std::string help,
std::map labels,
- uint32_t dupli_count = 2)
+ uint32_t dupli_count = (std::min)(
+ 128u, std::thread::hardware_concurrency()))
: static_metric(MetricType::Counter, std::move(name), std::move(help),
- std::move(labels)) {
- init_thread_local(dupli_count);
- }
-
- void init_thread_local(uint32_t dupli_count) {
- if (dupli_count > 0) {
- dupli_count_ = dupli_count;
- default_label_value_ = {dupli_count};
- }
-
- g_user_metric_count++;
- }
-
- virtual ~basic_static_counter() { g_user_metric_count--; }
+ std::move(labels)),
+ dupli_count_((std::max)(1u, dupli_count)),
+ default_label_value_(dupli_count_) {}
void inc(value_type val = 1) {
- if (val <= 0) {
+ if (val < 0) {
return;
}
-
-#ifdef __APPLE__
- if constexpr (std::is_floating_point_v) {
- mac_os_atomic_fetch_add(&default_label_value_.local_value(), val);
- }
- else {
- default_label_value_.inc(val);
+ if (!has_change_) [[unlikely]] {
+ has_change_ = true;
}
-#else
default_label_value_.inc(val);
-#endif
}
value_type update(value_type value) {
@@ -123,23 +77,33 @@ class basic_static_counter : public static_metric {
return;
}
- serialize_head(str);
+ metric_t::serialize_head(str);
serialize_default_label(str, value);
}
#ifdef CINATRA_ENABLE_METRIC_JSON
void serialize_to_json(std::string &str) override {
- if (default_label_value_.value() == 0) {
+ auto value = default_label_value_.value();
+ if (value == 0 && !has_change_) {
return;
}
- json_counter_t counter{name_, help_, std::string(metric_name())};
- auto value = default_label_value_.value();
- counter.metrics.push_back({static_labels_, value});
+ json_counter_t counter{name_, help_, metric_name()};
+
+ counter.labels_name.reserve(static_labels_.size());
+ for (auto &[k, _] : static_labels_) {
+ counter.labels_name.emplace_back(k);
+ }
+ counter.metrics.resize(1);
+ counter.metrics[0].labels.reserve(static_labels_.size());
+ for (auto &[k, _] : static_labels_) {
+ counter.metrics[0].labels.emplace_back(k);
+ }
+ counter.metrics[0].value = value;
iguana::to_json(counter, str);
}
#endif
-
+ private:
protected:
void serialize_default_label(std::string &str, value_type value) {
str.append(name_);
@@ -165,159 +129,48 @@ class basic_static_counter : public static_metric {
str.pop_back();
}
- thread_local_value default_label_value_;
- uint32_t dupli_count_ = 2;
bool has_change_ = false;
-};
-
-template
-struct array_hash {
- size_t operator()(const Key &arr) const {
- unsigned int seed = 131;
- unsigned int hash = 0;
-
- for (const auto &str : arr) {
- for (auto ch : str) {
- hash = hash * seed + ch;
- }
- }
-
- return (hash & 0x7FFFFFFF);
- }
+ uint32_t dupli_count_;
+ thread_local_value default_label_value_;
};
using counter_t = basic_static_counter;
using counter_d = basic_static_counter;
-template
-using dynamic_metric_hash_map = std::unordered_map>;
-
template
-class basic_dynamic_counter : public dynamic_metric {
+class basic_dynamic_counter
+ : public dynamic_metric_impl, N> {
+ using Base = dynamic_metric_impl, N>;
+
public:
// dynamic labels value
basic_dynamic_counter(std::string name, std::string help,
- std::array labels_name,
- size_t dupli_count = 2)
- : dynamic_metric(MetricType::Counter, std::move(name), std::move(help),
- std::move(labels_name)),
- dupli_count_(dupli_count) {
- g_user_metric_count++;
- }
-
- virtual ~basic_dynamic_counter() { g_user_metric_count--; }
-
- void inc(const std::array &labels_value,
- value_type value = 1) {
- if (value == 0) {
- return;
- }
-
- std::unique_lock lock(mtx_);
- if (value_map_.size() > ylt_label_capacity) {
- return;
- }
- auto [it, r] = value_map_.try_emplace(
- labels_value, thread_local_value(dupli_count_));
- lock.unlock();
- if (r) {
- g_user_metric_label_count->local_value()++;
- if (ylt_label_max_age.count()) {
- it->second.set_created_time(std::chrono::system_clock::now());
- }
- }
- set_value(it->second.local_value(), value, op_type_t::INC);
+ std::array labels_name)
+ : Base(MetricType::Counter, std::move(name), std::move(help),
+ std::move(labels_name)) {}
+ using label_key_type = const std::array &;
+ void inc(label_key_type labels_value, value_type value = 1) {
+ detail::inc_impl(Base::try_emplace(labels_value).first->value, value);
}
- value_type update(const std::array &labels_value,
- value_type value) {
- std::unique_lock lock(mtx_);
- if (value_map_.size() > ylt_label_capacity) {
- return value_type{};
- }
- if (!has_change_) [[unlikely]]
- has_change_ = true;
- auto [it, r] = value_map_.try_emplace(
- labels_value, thread_local_value(dupli_count_));
- lock.unlock();
- if (r) {
- g_user_metric_label_count->local_value()++;
- if (ylt_label_max_age.count()) {
- it->second.set_created_time(std::chrono::system_clock::now());
- }
- }
- return it->second.update(value);
- }
-
- value_type value(const std::array &labels_value) {
- std::lock_guard lock(mtx_);
- if (auto it = value_map_.find(labels_value); it != value_map_.end()) {
- return it->second.value();
- }
-
- return value_type{};
- }
-
- value_type reset() {
- value_type val = {};
-
- std::lock_guard lock(mtx_);
- for (auto &[key, t] : value_map_) {
- val += t.reset();
- }
-
- return val;
- }
-
- dynamic_metric_hash_map,
- thread_local_value>
- value_map() {
- [[maybe_unused]] bool has_change = false;
- return value_map(has_change);
+ value_type update(label_key_type labels_value, value_type value) {
+ return Base::try_emplace(labels_value)
+ .first->value.exchange(value, std::memory_order::relaxed);
}
- dynamic_metric_hash_map,
- thread_local_value>
- value_map(bool &has_change) {
- dynamic_metric_hash_map,
- thread_local_value>
- map;
- {
- std::lock_guard lock(mtx_);
- map = value_map_;
- has_change = has_change_;
+ value_type value(label_key_type labels_value) {
+ if (auto ptr = Base::find(labels_value); ptr != nullptr) {
+ return ptr->value.load(std::memory_order::relaxed);
}
-
- return map;
- }
-
- size_t label_value_count() override {
- std::lock_guard lock(mtx_);
- return value_map_.size();
- }
-
- void clean_expired_label() override {
- if (ylt_label_max_age.count() == 0) {
- return;
+ else {
+ return value_type{};
}
-
- auto now = std::chrono::system_clock::now();
- std::lock_guard lock(mtx_);
- std::erase_if(value_map_, [&now](auto &pair) mutable {
- bool r = std::chrono::duration_cast(
- now - pair.second.get_created_time())
- .count() >= ylt_label_max_age.count();
- return r;
- });
}
void remove_label_value(
const std::map &labels) override {
- {
- std::lock_guard lock(mtx_);
- if (value_map_.empty()) {
- return;
- }
+ if (Base::empty()) {
+ return;
}
const auto &labels_name = this->labels_name();
@@ -325,51 +178,43 @@ class basic_dynamic_counter : public dynamic_metric {
return;
}
- if (labels.size() == labels_name.size()) {
- std::vector label_value;
- for (auto &lb_name : labels_name) {
- if (auto i = labels.find(lb_name); i != labels.end()) {
- label_value.push_back(i->second);
- }
- }
+ // if (labels.size() == labels_name.size()) { // TODO: speed up for this
+ // case
- std::lock_guard lock(mtx_);
- std::erase_if(value_map_, [&, this](auto &pair) {
- return equal(label_value, pair.first);
- });
- return;
- }
- else {
- std::vector vec;
- for (auto &lb_name : labels_name) {
- if (auto i = labels.find(lb_name); i != labels.end()) {
- vec.push_back(i->second);
- }
- else {
- vec.push_back("");
- }
+ // }
+ // else {
+ size_t count = 0;
+ std::vector vec;
+ for (auto &lb_name : labels_name) {
+ if (auto i = labels.find(lb_name); i != labels.end()) {
+ vec.push_back(i->second);
}
- if (vec.empty()) {
- return;
+ else {
+ vec.push_back("");
+ count++;
}
-
- std::lock_guard lock(mtx_);
- std::erase_if(value_map_, [&](auto &pair) {
- auto &[arr, _] = pair;
+ }
+ if (count == labels_name.size()) {
+ return;
+ }
+ Base::erase_if([&](auto &pair) {
+ auto &[arr, _] = pair;
+ if constexpr (N > 0) {
for (size_t i = 0; i < vec.size(); i++) {
if (!vec[i].empty() && vec[i] != arr[i]) {
return false;
}
}
- return true;
- });
- }
+ }
+ return true;
+ });
+ //}
}
bool has_label_value(const std::string &value) override {
- [[maybe_unused]] bool has_change = false;
- auto map = value_map(has_change);
- for (auto &[label_value, _] : map) {
+ auto map = Base::copy();
+ for (auto &e : map) {
+ auto &label_value = e->label;
if (auto it = std::find(label_value.begin(), label_value.end(), value);
it != label_value.end()) {
return true;
@@ -380,9 +225,9 @@ class basic_dynamic_counter : public dynamic_metric {
}
bool has_label_value(const std::regex ®ex) override {
- [[maybe_unused]] bool has_change = false;
- auto map = value_map(has_change);
- for (auto &[label_value, _] : map) {
+ auto map = Base::copy();
+ for (auto &e : map) {
+ auto &label_value = e->label;
if (auto it = std::find_if(label_value.begin(), label_value.end(),
[&](auto &val) {
return std::regex_match(val, regex);
@@ -398,51 +243,53 @@ class basic_dynamic_counter : public dynamic_metric {
bool has_label_value(const std::vector &label_value) override {
std::array arr{};
size_t size = (std::min)((size_t)N, label_value.size());
+ if (label_value.size() > N) {
+ return false;
+ }
+
for (size_t i = 0; i < size; i++) {
arr[i] = label_value[i];
}
- std::lock_guard lock(mtx_);
- return value_map_.contains(arr);
+ return Base::find(arr) != nullptr;
}
void serialize(std::string &str) override {
- bool has_change = false;
- auto map = value_map(has_change);
+ auto map = Base::copy();
if (map.empty()) {
return;
}
std::string value_str;
- serialize_map(map, value_str, has_change);
+ serialize_map(map, value_str);
if (!value_str.empty()) {
- serialize_head(str);
+ Base::serialize_head(str);
str.append(value_str);
}
}
#ifdef CINATRA_ENABLE_METRIC_JSON
void serialize_to_json(std::string &str) override {
- std::string s;
- bool has_change = false;
- auto map = value_map(has_change);
- json_counter_t counter{name_, help_, std::string(metric_name())};
- to_json(counter, map, str, has_change);
+ auto map = Base::copy();
+ json_counter_t counter{Base::name_, Base::help_, Base::metric_name()};
+ counter.labels_name.reserve(Base::labels_name().size());
+ for (auto &e : Base::labels_name()) {
+ counter.labels_name.emplace_back(e);
+ }
+ to_json(counter, map, str);
}
template
- void to_json(json_counter_t &counter, T &map, std::string &str,
- bool has_change) {
- for (auto &[k, v] : map) {
- auto val = v.value();
- if (val == 0 && !has_change) {
- continue;
- }
+ void to_json(json_counter_t &counter, T &map, std::string &str) {
+ for (auto &e : map) {
+ auto &k = e->label;
+ auto &val = e->value;
json_counter_metric_t metric;
size_t index = 0;
+ metric.labels.reserve(k.size());
for (auto &label_value : k) {
- metric.labels.emplace(labels_name_[index++], label_value);
+ metric.labels.emplace_back(label_value);
}
- metric.value = (int64_t)val;
+ metric.value = val.load(std::memory_order::relaxed);
counter.metrics.push_back(std::move(metric));
}
if (!counter.metrics.empty()) {
@@ -453,19 +300,17 @@ class basic_dynamic_counter : public dynamic_metric {
protected:
template
- void serialize_map(T &value_map, std::string &str, bool has_change) {
- for (auto &[labels_value, value] : value_map) {
- auto val = value.value();
- if (val == 0 && !has_change) {
- continue;
- }
- str.append(name_);
- if (labels_name_.empty()) {
+ void serialize_map(T &value_map, std::string &str) {
+ for (auto &e : value_map) {
+ auto &labels_value = e->label;
+ auto val = e->value.load(std::memory_order::relaxed);
+ str.append(Base::name_);
+ if (Base::labels_name_.empty()) {
str.append(" ");
}
else {
str.append("{");
- build_string(str, labels_name_, labels_value);
+ build_string(str, Base::labels_name_, labels_value);
str.append("} ");
}
@@ -490,13 +335,6 @@ class basic_dynamic_counter : public dynamic_metric {
}
str.pop_back();
}
-
- std::mutex mtx_;
- dynamic_metric_hash_map,
- thread_local_value>
- value_map_;
- size_t dupli_count_ = 2;
- bool has_change_ = false;
};
using dynamic_counter_1t = basic_dynamic_counter;
diff --git a/include/ylt/metric/dynamic_metric.hpp b/include/ylt/metric/dynamic_metric.hpp
new file mode 100644
index 000000000..8858812f3
--- /dev/null
+++ b/include/ylt/metric/dynamic_metric.hpp
@@ -0,0 +1,132 @@
+#pragma once
+#include
+
+#include "metric.hpp"
+#include "thread_local_value.hpp"
+#include "ylt/util/map_sharded.hpp"
+
+namespace ylt::metric {
+
+class dynamic_metric : public metric_t {
+ public:
+ static inline auto g_user_metric_label_count =
+ new thread_local_value(std::thread::hardware_concurrency());
+ using metric_t::metric_t;
+};
+
+template
+class dynamic_metric_impl : public dynamic_metric {
+ template
+ struct my_hash {
+ using is_transparent = void;
+ std::size_t operator()(
+ const std::span& s) const noexcept {
+ unsigned int hash = 0;
+ for (const auto& str : s) {
+ for (auto ch : str) {
+ hash = hash * seed + ch;
+ }
+ }
+ return hash;
+ }
+ std::size_t operator()(
+ const std::span& s) const noexcept {
+ unsigned int hash = 0;
+ for (const auto& str : s) {
+ for (auto ch : str) {
+ hash = hash * seed + ch;
+ }
+ }
+ return hash;
+ }
+ };
+ struct my_equal {
+ bool operator()(const std::span& s1,
+ const std::span& s2) const noexcept {
+ if constexpr (N > 0) {
+ for (int i = 0; i < N; ++i) {
+ if (s1[i] != s2[i]) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ };
+ using key_type = std::array;
+ struct metric_pair {
+ public:
+ key_type label;
+ core_type value;
+ template
+ metric_pair(T&& first, Args&&... args)
+ : label(std::forward(first)), value(std::forward(args)...) {
+ g_user_metric_label_count->inc();
+ if (ylt_label_max_age.count()) {
+ tp = std::chrono::steady_clock::now();
+ }
+ }
+ std::chrono::steady_clock::time_point get_created_time() const {
+ return tp;
+ }
+
+ private:
+ std::chrono::steady_clock::time_point tp;
+ };
+
+ struct value_type : public std::shared_ptr {
+ value_type() : std::shared_ptr(nullptr) {}
+ template
+ value_type(Args&&... args)
+ : std::shared_ptr(
+ std::make_shared(std::forward(args)...)){};
+ };
+
+ public:
+ using dynamic_metric::dynamic_metric;
+ size_t size() const { return map_.size(); }
+ size_t empty() const { return !size(); }
+ size_t label_value_count() const { return size(); }
+
+ std::vector> copy() const {
+ return map_.template copy>();
+ }
+
+ void clean_expired_label() override {
+ erase_if([now = std::chrono::steady_clock::now()](auto& pair) mutable {
+ bool r = std::chrono::duration_cast(
+ now - pair.second->get_created_time())
+ .count() >= ylt_label_max_age.count();
+ return r;
+ });
+ }
+
+ protected:
+ template
+ std::pair, bool> try_emplace(Key&& key,
+ Args&&... args) {
+ std::span view = key;
+ return map_.try_emplace_with_op(
+ view,
+ [](auto result) {
+ if (result.second) {
+ *const_cast*>(
+ &result.first->first) = result.first->second->label;
+ }
+ },
+ std::forward(key), std::forward(args)...);
+ }
+
+ std::shared_ptr find(std::span key) const {
+ return map_.find(key);
+ }
+ size_t erase(std::span key) { return map_.erase(key); }
+ size_t erase_if(auto&& op) { return map_.erase_if(op); }
+
+ private:
+ util::map_sharded_t,
+ value_type, my_hash<131>, my_equal>,
+ my_hash<137>>
+ map_{std::min(128u, std::thread::hardware_concurrency())};
+};
+} // namespace ylt::metric
diff --git a/include/ylt/metric/gauge.hpp b/include/ylt/metric/gauge.hpp
index 50d678c1c..41b689a4a 100644
--- a/include/ylt/metric/gauge.hpp
+++ b/include/ylt/metric/gauge.hpp
@@ -1,7 +1,9 @@
#pragma once
+#include
#include
#include "counter.hpp"
+#include "ylt/metric/metric.hpp"
namespace ylt::metric {
@@ -32,16 +34,7 @@ class basic_static_gauge : public basic_static_counter {
if (!has_change_) [[unlikely]] {
has_change_ = true;
}
-#ifdef __APPLE__
- if constexpr (std::is_floating_point_v) {
- mac_os_atomic_fetch_sub(&default_label_value_.local_value(), value);
- }
- else {
- default_label_value_.dec(value);
- }
-#else
default_label_value_.dec(value);
-#endif
}
};
using gauge_t = basic_static_gauge;
@@ -50,44 +43,18 @@ using gauge_d = basic_static_gauge;
template
class basic_dynamic_gauge : public basic_dynamic_counter {
using metric_t::set_metric_type;
- using basic_dynamic_counter::value_map_;
- using basic_dynamic_counter::mtx_;
- using basic_dynamic_counter::dupli_count_;
- using basic_dynamic_counter::has_change_;
+ using Base = basic_dynamic_counter;
public:
basic_dynamic_gauge(std::string name, std::string help,
- std::array labels_name,
- size_t dupli_count = 2)
- : basic_dynamic_counter(std::move(name), std::move(help),
- std::move(labels_name),
- dupli_count) {
+ std::array labels_name)
+ : Base(std::move(name), std::move(help), std::move(labels_name)) {
set_metric_type(MetricType::Gauge);
}
void dec(const std::array& labels_value,
value_type value = 1) {
- if (value == 0) {
- return;
- }
-
- std::unique_lock lock(mtx_);
- if (value_map_.size() > ylt_label_capacity) {
- return;
- }
- if (!has_change_) [[unlikely]]
- has_change_ = true;
- auto [it, r] = value_map_.try_emplace(
- labels_value, thread_local_value(dupli_count_));
- lock.unlock();
- if (r) {
- g_user_metric_label_count->local_value()++;
- if (ylt_label_max_age.count()) {
- it->second.set_created_time(std::chrono::system_clock::now());
- }
- }
-
- set_value(it->second.local_value(), value, op_type_t::DEC);
+ detail::dec_impl(Base::try_emplace(labels_value).first->value, value);
}
};
diff --git a/include/ylt/metric/histogram.hpp b/include/ylt/metric/histogram.hpp
index 66c13d018..ce897a452 100644
--- a/include/ylt/metric/histogram.hpp
+++ b/include/ylt/metric/histogram.hpp
@@ -6,7 +6,8 @@
#include
#include "counter.hpp"
-#include "metric.hpp"
+#include "dynamic_metric.hpp"
+#include "gauge.hpp"
namespace ylt::metric {
#ifdef CINATRA_ENABLE_METRIC_JSON
@@ -140,8 +141,6 @@ class basic_static_histogram : public static_metric {
private:
void init_bucket_counter(size_t dupli_count, size_t bucket_size) {
- g_user_metric_count++;
-
for (size_t i = 0; i < bucket_size + 1; i++) {
bucket_counts_.push_back(
std::make_shared("", "", dupli_count));
@@ -167,18 +166,15 @@ class basic_dynamic_histogram : public dynamic_metric {
public:
basic_dynamic_histogram(std::string name, std::string help,
std::vector buckets,
- std::array labels_name,
- size_t dupli_count = 2)
+ std::array labels_name)
: bucket_boundaries_(buckets),
dynamic_metric(MetricType::Histogram, name, help, labels_name),
sum_(std::make_shared>(
- name, help, labels_name, dupli_count)) {
- g_user_metric_count++;
-
+ name, help, labels_name)) {
for (size_t i = 0; i < buckets.size() + 1; i++) {
bucket_counts_.push_back(
- std::make_shared>(
- name, help, labels_name, dupli_count));
+ std::make_shared>(name, help,
+ labels_name));
}
}
@@ -192,6 +188,13 @@ class basic_dynamic_histogram : public dynamic_metric {
bucket_counts_[bucket_index]->inc(labels_value);
}
+ void clean_expired_label() override {
+ sum_->clean_expired_label();
+ for (auto &m : bucket_counts_) {
+ m->clean_expired_label();
+ }
+ }
+
auto get_bucket_counts() { return bucket_counts_; }
bool has_label_value(const std::string &label_val) override {
@@ -206,8 +209,10 @@ class basic_dynamic_histogram : public dynamic_metric {
return sum_->has_label_value(label_value);
}
+ size_t label_value_count() const { return sum_->label_value_count(); }
+
void serialize(std::string &str) override {
- auto value_map = sum_->value_map();
+ auto value_map = sum_->copy();
if (value_map.empty()) {
return;
}
@@ -216,8 +221,10 @@ class basic_dynamic_histogram : public dynamic_metric {
std::string value_str;
auto bucket_counts = get_bucket_counts();
- for (auto &[labels_value, value] : value_map) {
- if (value.value() == 0) {
+ for (auto &e : value_map) {
+ auto &labels_value = e->label;
+ auto &value = e->value;
+ if (value == 0) {
continue;
}
@@ -244,10 +251,6 @@ class basic_dynamic_histogram : public dynamic_metric {
value_str.append("\n");
}
- if (value_str.empty()) {
- return;
- }
-
str.append(value_str);
str.append(name_);
@@ -255,7 +258,7 @@ class basic_dynamic_histogram : public dynamic_metric {
build_label_string(str, sum_->labels_name(), labels_value);
str.append("} ");
- str.append(std::to_string(value.value()));
+ str.append(std::to_string(value));
str.append("\n");
str.append(name_).append("_count{");
@@ -264,11 +267,14 @@ class basic_dynamic_histogram : public dynamic_metric {
str.append(std::to_string(count));
str.append("\n");
}
+ if (value_str.empty()) {
+ str.clear();
+ }
}
#ifdef CINATRA_ENABLE_METRIC_JSON
void serialize_to_json(std::string &str) override {
- auto value_map = sum_->value_map();
+ auto value_map = sum_->copy();
if (value_map.empty()) {
return;
}
@@ -276,8 +282,10 @@ class basic_dynamic_histogram : public dynamic_metric {
json_histogram_t hist{name_, help_, std::string(metric_name())};
auto bucket_counts = get_bucket_counts();
- for (auto &[labels_value, value] : value_map) {
- if (value.value() == 0) {
+ for (auto &e : value_map) {
+ auto &labels_value = e->label;
+ auto &value = e->value;
+ if (value == 0) {
continue;
}
diff --git a/include/ylt/metric/metric.hpp b/include/ylt/metric/metric.hpp
index 8c880765e..67e90d9bc 100644
--- a/include/ylt/metric/metric.hpp
+++ b/include/ylt/metric/metric.hpp
@@ -1,21 +1,18 @@
#pragma once
#include
#include
-#include
-#include