Compare commits

..

16 Commits

Author SHA1 Message Date
Chris Gundlach efd3086af2 added prometheus-cpp as a submodule 2022-10-07 13:03:53 -05:00
Chris Gundlach 30f69ec758 Merge branch 'feature_prometheus_plugin' of https://github.com/AntelopeIO/leap into feature_prometheus_plugin 2022-10-06 10:28:32 -05:00
Chris Gundlach c673e984b0 Merge branch 'main' into feature_prometheus_plugin 2022-10-06 10:26:07 -05:00
Christopher Gundlach 26b8e59066 Merge pull request #258 from AntelopeIO/add_prometheus_library
Add Prometheus Library
2022-09-29 14:57:33 -05:00
Chris Gundlach b8b0e75513 removed PROMETHEUS_INSTALL_COMPONENT 2022-09-29 12:05:43 -05:00
Chris Gundlach 472ccc3929 took out cmake cruft 2022-09-29 12:01:36 -05:00
Chris Gundlach b16ed1de3b Merge branch 'main' into feature_prometheus_plugin 2022-09-29 10:22:19 -05:00
Chris Gundlach 167f9216be updated prometheus_plugin to be dependent on prometheus library 2022-09-29 10:14:14 -05:00
Chris Gundlach 1a9de428cb added prometheus library 2022-09-29 10:13:13 -05:00
Chris Gundlach eaeaf4ab3d Merge branch 'main' into feature_prometheus_plugin 2022-09-27 09:26:53 -05:00
Christopher Gundlach cf24fe9cbf Merge pull request #190 from AntelopeIO/add_prometheus_plugin
Add Prometheus Plugin
2022-09-20 14:10:21 -05:00
Chris Gundlach d351840a70 changed to make building prometheus plugin mandatory 2022-09-20 09:16:40 -05:00
Chris Gundlach 78c6c77c00 took out unecessary includes/dependencies 2022-09-19 14:58:20 -05:00
Chris Gundlach 46582601ea took out unnecessary include/lib paths 2022-09-19 14:57:53 -05:00
Chris Gundlach cdb4156702 added prometheus plugin skeleton code 2022-09-19 14:22:21 -05:00
Chris Gundlach 642653a37f cmake changes to add prometheus plugin 2022-09-19 14:21:08 -05:00
217 changed files with 9360 additions and 823 deletions
+3
View File
@@ -7,10 +7,13 @@ RUN apt-get update && apt-get upgrade -y && \
g++-8 \
git \
jq \
libcurl4-openssl-dev \
libgmp-dev \
libssl-dev \
libusb-1.0-0-dev \
llvm-7-dev \
ninja-build \
pkg-config \
python3 \
software-properties-common \
zlib1g-dev \
+3
View File
@@ -7,8 +7,11 @@ RUN apt-get update && apt-get upgrade -y && \
git \
jq \
libboost-all-dev \
libcurl4-openssl-dev \
libgmp-dev \
libssl-dev \
libusb-1.0-0-dev \
llvm-11-dev \
ninja-build \
pkg-config \
zstd
+3
View File
@@ -7,8 +7,11 @@ RUN apt-get update && apt-get upgrade -y && \
git \
jq \
libboost-all-dev \
libcurl4-openssl-dev \
libgmp-dev \
libssl-dev \
libusb-1.0-0-dev \
llvm-11-dev \
ninja-build \
pkg-config \
zstd
-1
View File
@@ -12,7 +12,6 @@ jobs:
label: triage
org-project: 'Team Backlog'
project-field: Status=Todo
skip-if-existing-project: true
secrets:
token: ${{secrets.ENFCIBOT_REPO_AND_PROJECTS}}
-2
View File
@@ -79,8 +79,6 @@ Testing/*
build.tar.gz
build/*
build-debug/*
deps/*
dependencies/*
etc/eosio/node_*
var/lib/node_*
+6
View File
@@ -13,6 +13,9 @@
[submodule "libraries/rapidjson"]
path = libraries/rapidjson
url = https://github.com/Tencent/rapidjson/
[submodule "libraries/yubihsm"]
path = libraries/yubihsm
url = https://github.com/Yubico/yubihsm-shell
[submodule "tests/abieos"]
path = tests/abieos
url = https://github.com/AntelopeIO/abieos
@@ -25,3 +28,6 @@
[submodule "libraries/libfc/libraries/ff"]
path = libraries/libfc/libraries/ff
url = https://github.com/AntelopeIO/libff
[submodule "libraries/prometheus-cpp"]
path = libraries/prometheus-cpp
url = https://github.com/jupp0r/prometheus-cpp.git
+8 -2
View File
@@ -13,8 +13,8 @@ set( CMAKE_CXX_STANDARD 17 )
set( CMAKE_CXX_EXTENSIONS ON )
set( CXX_STANDARD_REQUIRED ON)
set(VERSION_MAJOR 4)
set(VERSION_MINOR 0)
set(VERSION_MAJOR 3)
set(VERSION_MINOR 2)
set(VERSION_PATCH 0)
set(VERSION_SUFFIX dev)
@@ -60,6 +60,8 @@ if(APPLE AND UNIX AND "${OPENSSL_ROOT_DIR}" STREQUAL "")
set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl@3;/usr/local/opt/openssl@1.1")
endif()
endif()
# fc also adds these definitions to its public interface. once fc becomes the sole importer of openssl, this should be removed
add_definitions(-DOPENSSL_API_COMPAT=0x10100000L -DOPENSSL_NO_DEPRECATED)
option(ENABLE_OC "Enable eosvm-oc on supported platforms" ON)
@@ -222,6 +224,7 @@ configure_file(libraries/libfc/src/network/LICENSE.go licen
configure_file(libraries/eos-vm/LICENSE licenses/leap/LICENSE.eos-vm COPYONLY)
configure_file(libraries/libfc/libraries/ff/LICENSE licenses/leap/LICENSE.libff COPYONLY)
configure_file(programs/cleos/LICENSE.CLI11 licenses/leap/LICENSE.CLI11 COPYONLY)
configure_file(libraries/yubihsm/LICENSE licenses/leap/LICENSE.yubihsm COPYONLY)
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/licenses/leap" DESTINATION "${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/" COMPONENT base)
@@ -240,6 +243,9 @@ add_custom_target(dev-install
USES_TERMINAL
)
get_property(_CTEST_CUSTOM_TESTS_IGNORE GLOBAL PROPERTY CTEST_CUSTOM_TESTS_IGNORE)
file(WRITE "${CMAKE_BINARY_DIR}/CTestCustom.cmake" "SET(CTEST_CUSTOM_TESTS_IGNORE ${_CTEST_CUSTOM_TESTS_IGNORE})")
include(doxygen)
include(package.cmake)
+1 -1
View File
@@ -51,7 +51,7 @@ find_package(Boost @Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@ EXACT REQUIRED CO
find_library(libtester eosio_testing @CMAKE_BINARY_DIR@/libraries/testing NO_DEFAULT_PATH)
find_library(libchain eosio_chain @CMAKE_BINARY_DIR@/libraries/chain NO_DEFAULT_PATH)
find_library(libfc fc @CMAKE_BINARY_DIR@/libraries/libfc NO_DEFAULT_PATH)
find_library(libfc fc @CMAKE_BINARY_DIR@/libraries/fc NO_DEFAULT_PATH)
find_library(libsecp256k1 secp256k1 @CMAKE_BINARY_DIR@/libraries/libfc/secp256k1 NO_DEFAULT_PATH)
find_library(libff ff @CMAKE_BINARY_DIR@/libraries/libfc/libraries/ff/libff NO_DEFAULT_PATH)
+92 -215
View File
@@ -1,249 +1,126 @@
# Leap
Leap is a C++ implementation of the [Antelope](https://github.com/AntelopeIO) protocol. It contains blockchain node software and supporting tools for developers and node operators.
## Branches
The `main` branch is the development branch; do not use it for production. Refer to the [release page](https://github.com/AntelopeIO/leap/releases) for current information on releases, pre-releases, and obsolete releases, as well as the corresponding tags for those releases.
Leap is blockchain node software and supporting tools that implements the [Antelope](https://github.com/AntelopeIO) protocol.
## Supported Operating Systems
We currently support the following operating systems.
- Ubuntu 22.04 Jammy
- Ubuntu 20.04 Focal
- Ubuntu 18.04 Bionic
## Repo Organization
Other Unix derivatives such as macOS are tended to on a best-effort basis and may not be full featured. If you aren't using Ubuntu, please visit the "[Build Unsupported OS](./docs/00_install/01_build-from-source/00_build-unsupported-os.md)" page to explore your options.
`main` branch is the development branch: do not use this for production. Refer to the [release page](https://github.com/AntelopeIO/leap/releases) for current information on releases, pre-releases, and obsolete releases as well as the corresponding tags for those releases.
If you are running an unsupported Ubuntu derivative, such as Linux Mint, you can find the version of Ubuntu your distribution was based on by using this command:
```bash
cat /etc/upstream-release/lsb-release
## Software Installation
Visit the [release page](https://github.com/AntelopeIO/leap/releases) for Ubuntu binaries. This is the fastest way to get started with the software.
### Building From Source
Recent Ubuntu LTS releases are the only Linux distributions that we fully support. Other Linux distros and other POSIX operating systems (such as macOS) are tended to on a best-effort basis and may not be full featured. Notable requirements to build are:
* C++17 compiler and standard library
* boost 1.67+
* CMake 3.8+
* (for Linux only) LLVM 7 - 11 (newer versions do not work)
A few other common libraries are tools also required such as openssl 1.1+, libcurl, curl, libusb, GMP, Python 3, and zlib.
**A Warning On Parallel Compilation Jobs (`-j` flag)**: When building C/C++ software often the build is performed in parallel via a command such as `make -j $(nproc)` which uses the number of CPU cores as the number of compilation jobs to perform simultaneously. However, be aware that some compilation units (.cpp files) in Leap are extremely complex and will consume nearly 4GB of memory to compile. You may need to reduce the level of parallelization depending on the amount of memory on your build host. e.g. instead of `make -j $(nproc)` run `make -j2`. Failures due to memory exhaustion will typically but not always manifest as compiler crashes.
Generally we recommend performing what we refer to as a "pinned build" which ensures the compiler and boost version remain the same between builds of different Leap versions (Leap requires these versions remain the same otherwise its state needs to be repopulated from a portable snapshot).
#### Building Pinned Build Binary Packages
In the directory `<leap src>/scripts` you will find the two scripts `install_deps.sh` and `pinned_build.sh`. If you haven't installed build dependencies then run `install_deps.sh`. Then run `pinned_build.sh <dependencies directory> <leap build directory> <number of jobs>`.
The dependencies directory is where the script will pull the C++ dependencies that need to be built with the pinned compiler for building the pinned binaries for binary packaging.
The binary package will be produced in the Leap build directory that was supplied.
#### Manual (non "pinned") Build Instructions
<details>
<summary>Ubuntu 20.04 & 22.04 Build Instructions</summary>
Install required dependencies:
```
Your best bet is to follow the instructions for your Ubuntu base, but we make no guarantees.
## Binary Installation
This is the fastest way to get started. From the [latest release](https://github.com/AntelopeIO/leap/releases/latest) page, download a binary for one of our [supported operating systems](#supported-operating-systems), or visit the [release tags](https://github.com/AntelopeIO/leap/releases) page to download a binary for a specific version of Leap.
Once you have a `*.deb` file downloaded for your version of Ubuntu, you can install it as follows:
```bash
sudo apt-get update
sudo apt-get install -y ~/Downloads/leap*.deb
apt-get update && apt-get install \
build-essential \
cmake \
curl \
git \
libboost-all-dev \
libcurl4-openssl-dev \
libgmp-dev \
libssl-dev \
libusb-1.0-0-dev \
llvm-11-dev \
pkg-config
```
Your download path may vary. If you are in an Ubuntu docker container, omit `sudo` because you run as `root` by default.
Finally, verify Leap was installed correctly:
```bash
nodeos --full-version
and perform the build:
```
You should see a [semantic version](https://semver.org) string followed by a `git` commit hash with no errors. For example:
```
v3.1.2-0b64f879e3ebe2e4df09d2e62f1fc164cc1125d1
```
## Build and Install from Source
You can also build and install Leap from source.
### Prerequisites
You will need to build on a [supported operating system](#supported-operating-systems).
Requirements to build:
- C++17 compiler and standard library
- boost 1.67+
- CMake 3.8+
- LLVM 7 - 11 - for Linux only
- newer versions do not work
- openssl 1.1+
- curl
- git
- GMP
- Python 3
- zlib
### Step 1 - Clone
If you don't have the Leap repo cloned to your computer yet, [open a terminal](https://itsfoss.com/open-terminal-ubuntu) and navigate to the folder where you want to clone the Leap repository:
```bash
cd ~/Downloads
```
Clone Leap using either HTTPS...
```bash
git clone --recursive https://github.com/AntelopeIO/leap.git
```
...or SSH:
```bash
git clone --recursive git@github.com:AntelopeIO/leap.git
```
> ️ **HTTPS vs. SSH Clone**
Both an HTTPS or SSH git clone will yield the same result - a folder named `leap` containing our source code. It doesn't matter which type you use.
Navigate into that folder:
```bash
cd leap
```
### Step 2 - Checkout Release Tag or Branch
Choose which [release](https://github.com/AntelopeIO/leap/releases) or [branch](#branches) you would like to build, then check it out. If you are not sure, use the [latest release](https://github.com/AntelopeIO/leap/releases/latest). For example, if you want to build release 3.1.2 then you would check it out using its tag, `v3.1.2`. In the example below, replace `v0.0.0` with your selected release tag accordingly:
```bash
git fetch --all --tags
git checkout v0.0.0
```
Once you are on the branch or release tag you want to build, make sure everything is up-to-date:
```bash
git pull
git submodule update --init --recursive
```
### Step 3 - Build
Select build instructions below for a [pinned build](#pinned-build) (preferred) or an [unpinned build](#unpinned-build).
> ️ **Pinned vs. Unpinned Build**
We have two types of builds for Leap: "pinned" and "unpinned." The only difference is that pinned builds use specific versions for some dependencies hand-picked by the Leap engineers - they are "pinned" to those versions. In contrast, unpinned builds use the default dependency versions available on the build system at the time. We recommend performing a "pinned" build to ensure the compiler and boost versions remain the same between builds of different Leap versions. Leap requires these versions to remain the same, otherwise its state might need to be recovered from a portable snapshot or the chain needs to be replayed.
> ⚠️ **A Warning On Parallel Compilation Jobs (`-j` flag)** ⚠️
When building C/C++ software, often the build is performed in parallel via a command such as `make -j "$(nproc)"` which uses all available CPU threads. However, be aware that some compilation units (`*.cpp` files) in Leap will consume nearly 4GB of memory. Failures due to memory exhaustion will typically, but not always, manifest as compiler crashes. Using all available CPU threads may also prevent you from doing other things on your computer during compilation. For these reasons, consider reducing this value.
> 🐋 **Docker and `sudo`** 🐋
If you are in an Ubuntu docker container, omit `sudo` from all commands because you run as `root` by default. Most other docker containers also exclude `sudo`, especially Debian-family containers. If your shell prompt is a hash tag (`#`), omit `sudo`.
#### Pinned Build
Make sure you are in the root of the `leap` repo, then run the `install_depts.sh` script to install dependencies:
```bash
sudo scripts/install_deps.sh
```
Next, run the pinned build script. You have to give it three arguments, in the following order:
- A temporary folder, for all dependencies that need to be built from source.
- A build folder, where the binaries you need to install will be built to.
- The number of jobs or CPU cores/threads to use (note the [jobs flag](#step-3---build) warning above).
The following command runs the `pinned_build.sh` script, specifies a `deps` and `build` folder in the root of the Leap repo for the first two arguments, then builds the packages using all of your computer's CPU threads (Note: you don't need `sudo` for this command):
```bash
scripts/pinned_build.sh deps build "$(nproc)"
```
Now you can optionally [test](#step-4---test) your build, or [install](#step-5---install) the `*.deb` binary packages, which will be in the root of your build directory.
#### Unpinned Build
The following instructions are valid for this branch. Other release branches may have different requirements, so ensure you follow the directions in the branch or release you intend to build. If you are in an Ubuntu docker container, omit `sudo` because you run as `root` by default.
<details> <summary>Ubuntu 22.04 Jammy & Ubuntu 20.04 Focal</summary>
Install dependencies:
```bash
sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
curl \
git \
libboost-all-dev \
libgmp-dev \
libssl-dev \
llvm-11-dev
```
To build, make sure you are in the root of the `leap` repo, then run the following command:
```bash
mkdir -p build
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=/usr/lib/llvm-11 ..
make -j "$(nproc)" package
make -j $(nproc) package
```
</details>
<details> <summary>Ubuntu 18.04 Bionic</summary>
<details>
<summary>Ubuntu 18.04 Build Instructions</summary>
Install dependencies:
```bash
sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
curl \
g++-8 \
git \
libgmp-dev \
libssl-dev \
llvm-7-dev \
python3 \
Install required dependencies. You will need to build Boost from source on this distribution.
```
apt-get update && apt-get install \
build-essential \
cmake \
curl \
g++-8 \
git \
libcurl4-openssl-dev \
libgmp-dev \
libssl-dev \
libusb-1.0-0-dev \
llvm-7-dev \
pkg-config \
python3 \
zlib1g-dev
curl -L https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.tar.bz2 | tar jx && \
cd boost_1_79_0 && \
./bootstrap.sh --prefix=$HOME/boost1.79 && \
./b2 --with-iostreams --with-date_time --with-filesystem --with-system \
--with-program_options --with-chrono --with-test -j$(nproc) install && \
cd ..
```
You need to build Boost from source on this distribution:
```bash
curl -fL https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.tar.bz2 -o ~/Downloads/boost_1_79_0.tar.bz2
tar -jvxf ~/Downloads/boost_1_79_0.tar.bz2 -C ~/Downloads/
pushd ~/Downloads/boost_1_79_0
./bootstrap.sh --prefix="$HOME/boost1.79"
./b2 --with-iostreams --with-date_time --with-filesystem --with-system --with-program_options --with-chrono --with-test -j "$(nproc)" install
popd
and perform the build:
```
The Boost `*.tar.bz2` download and `boost_1_79_0` folder can be removed now if you want more space.
```bash
rm -r ~/Downloads/boost_1_79_0.tar.bz2 ~/Downloads/boost_1_79_0
```
From a terminal in the root of the `leap` repo, build.
```bash
mkdir -p build
git submodule update --init --recursive
mkdir build
cd build
cmake -DCMAKE_C_COMPILER=gcc-8 -DCMAKE_CXX_COMPILER=g++-8 -DCMAKE_PREFIX_PATH="$HOME/boost1.79;/usr/lib/llvm-7/" -DCMAKE_BUILD_TYPE=Release ..
make -j "$(nproc)" package
cmake -DCMAKE_C_COMPILER=gcc-8 -DCMAKE_CXX_COMPILER=g++-8 \
-DCMAKE_PREFIX_PATH="$HOME/boost1.79;/usr/lib/llvm-7/" -DCMAKE_BUILD_TYPE=Release .. \
make -j $(nproc) package
```
After building, you may remove the `~/boost1.79` directory or you may keep it around for your next build.
After building you may remove the `$HOME/boost1.79` directory, or you may keep it around until next time building the software.
</details>
Now you can optionally [test](#step-4---test) your build, or [install](#step-5---install) the `*.deb` binary packages, which will be in the root of your build directory.
### Running Tests
### Step 4 - Test
Leap supports the following test suites:
When building from source it's recommended to run at least what we refer to as the "parallelizable tests". Not included by default in the "parallelizable tests" are the WASM spec tests which can add additional coverage and can also be run in parallel.
Test Suite | Test Type | [Test Size](https://testing.googleblog.com/2010/12/test-sizes.html) | Notes
---|:---:|:---:|---
[Parallelizable tests](#parallelizable-tests) | Unit tests | Small
[WASM spec tests](#wasm-spec-tests) | Unit tests | Small | Unit tests for our WASM runtime, each short but _very_ CPU-intensive
[Serial tests](#serial-tests) | Component/Integration | Medium
[Long-running tests](#long-running-tests) | Integration | Medium-to-Large | Tests which take an extraordinarily long amount of time to run
```
cd build
When building from source, we recommended running at least the [parallelizable tests](#parallelizable-tests).
# "parallelizable tests": the minimum test set that should be run
ctest -j $(nproc) -LE _tests
#### Parallelizable Tests
This test suite consists of any test that does not require shared resources, such as file descriptors, specific folders, or ports, and can therefore be run concurrently in different threads without side effects (hence, easily parallelized). These are mostly unit tests and [small tests](https://testing.googleblog.com/2010/12/test-sizes.html) which complete in a short amount of time.
You can invoke them by running `ctest` from a terminal in your Leap build directory and specifying the following arguments:
```bash
ctest -j "$(nproc)" -LE _tests
# Also consider running the WASM spec tests for more coverage
ctest -j $(nproc) -L wasm_spec_tests
```
#### WASM Spec Tests
The WASM spec tests verify that our WASM execution engine is compliant with the web assembly standard. These are very [small](https://testing.googleblog.com/2010/12/test-sizes.html), very fast unit tests. However, there are over a thousand of them so the suite can take a little time to run. These tests are extremely CPU-intensive.
You can invoke them by running `ctest` from a terminal in your Leap build directory and specifying the following arguments:
```bash
ctest -j "$(nproc)" -L wasm_spec_tests
Some other tests are available and recommended but be aware they can be sensitive to other software running on the same host and they may **SIGKILL** other nodeos instances running on the host.
```
We have observed severe performance issues when multiple virtual machines are running this test suite on the same physical host at the same time, for example in a CICD system. This can be resolved by disabling hyperthreading on the host.
cd build
#### Serial Tests
The serial test suite consists of [medium](https://testing.googleblog.com/2010/12/test-sizes.html) component or integration tests that use specific paths, ports, rely on process names, or similar, and cannot be run concurrently with other tests. Serial tests can be sensitive to other software running on the same host and they may `SIGKILL` other `nodeos` processes. These tests take a moderate amount of time to complete, but we recommend running them.
You can invoke them by running `ctest` from a terminal in your Leap build directory and specifying the following arguments:
```bash
# These tests can't run in parallel but are recommended.
ctest -L "nonparallelizable_tests"
```
#### Long-Running Tests
The long-running tests are [medium-to-large](https://testing.googleblog.com/2010/12/test-sizes.html) integration tests that rely on shared resources and take a very long time to run.
You can invoke them by running `ctest` from a terminal in your Leap build directory and specifying the following arguments:
```bash
# These tests can't run in parallel. They also take a long time to run.
ctest -L "long_running_tests"
```
### Step 5 - Install
Once you have [built](#step-3---build-the-source-code) Leap and [tested](#step-4---test) your build, you can install Leap on your system. Don't forget to omit `sudo` if you are running in a docker container.
We recommend installing the binary package you just built. Navigate to your Leap build directory in a terminal and run this command:
```bash
sudo apt-get update
sudo apt-get install -y ./leap[-_][0-9]*.deb
```
It is also possible to install using `make` instead:
```bash
sudo make install
```
+65
View File
@@ -0,0 +1,65 @@
{
"name": "eos",
"generators": [
{
"name": "collate_markdown",
"options": {
"docs_dir": "docs"
}
},
{
"name": "swagger",
"options": {
"swagger_path": "plugins/chain_api_plugin/chain.swagger.yaml",
"swagger_dest_path": "nodeos/plugins/chain_api_plugin/api-reference",
"disable_filters": true,
"disable_summary_gen": true
}
},
{
"name": "swagger",
"options": {
"swagger_path": "plugins/db_size_api_plugin/db_size.swagger.yaml",
"swagger_dest_path": "nodeos/plugins/db_size_api_plugin/api-reference",
"disable_filters": true,
"disable_summary_gen": true
}
},
{
"name": "swagger",
"options": {
"swagger_path": "plugins/producer_api_plugin/producer.swagger.yaml",
"swagger_dest_path": "nodeos/plugins/producer_api_plugin/api-reference",
"disable_filters": true,
"disable_summary_gen": true
}
},
{
"name": "swagger",
"options": {
"swagger_path": "plugins/net_api_plugin/net.swagger.yaml",
"swagger_dest_path": "nodeos/plugins/net_api_plugin/api-reference",
"disable_filters": true,
"disable_summary_gen": true
}
},
{
"name": "swagger",
"options": {
"swagger_path": "plugins/test_control_api_plugin/test_control.swagger.yaml",
"swagger_dest_path": "nodeos/plugins/test_control_api_plugin/api-reference",
"disable_filters": true,
"disable_summary_gen": true
}
},
{
"name": "swagger",
"options": {
"swagger_path": "plugins/trace_api_plugin/trace_api.swagger.yaml",
"swagger_dest_path": "nodeos/plugins/trace_api_plugin/api-reference",
"disable_filters": true,
"disable_summary_gen": true
}
}
]
}
+110 -6
View File
@@ -2,19 +2,123 @@
content_title: Build Antelope from Source
---
The shell scripts previously recommended for building the software have been removed in favor of a build process entirely driven by CMake. Those wishing to build from source are now responsible for installing the necessary dependencies. The list of dependencies and the recommended build procedure are in the [`README.md`](https://github.com/AntelopeIO/leap/blob/main/README.md) file. Instructions are also included for efficiently running the tests.
The shell scripts previously recommended for building the software have been removed in favor of a build process entirely driven by CMake. Those wishing to build from source are now responsible for installing the necessary dependencies. The list of dependencies and the recommended build procedure are in the README.md file. Instructions are also included for efficiently running the tests.
### Using DUNE
As an alternative to building from source, try [Docker Utilities for Node Execution](https://github.com/AntelopeIO/DUNE) for the easiest way to get started and for multi-platform support.
As an alternative to building from source try [Docker Utilities for Node Execution](https://github.com/AntelopeIO/DUNE) for the easiest way to get started, and for multi-platform support.
### Building From Source
You can also build and install Leap from source. Instructions for that currently live [here](https://github.com/AntelopeIO/leap/blob/main/README.md#build-and-install-from-source).
Recent Ubuntu LTS releases are the only Linux distributions that we fully support. Other Linux distros and other POSIX operating systems (such as macOS) are tended to on a best-effort basis and may not be full featured. Notable requirements to build are:
* C++17 compiler and standard library
* boost 1.67+
* CMake 3.8+
* (for Linux only) LLVM 7 - 11 (newer versions do not work)
A few other common libraries are tools also required such as openssl 1.1+, libcurl, curl, libusb, GMP, Python 3, and zlib.
**A Warning On Parallel Compilation Jobs (`-j` flag)**: When building C/C++ software often the build is performed in parallel via a command such as `make -j $(nproc)` which uses the number of CPU cores as the number of compilation jobs to perform simultaneously. However, be aware that some compilation units (.cpp files) in mandel are extremely complex and will consume nearly 4GB of memory to compile. You may need to reduce the level of parallelization depending on the amount of memory on your build host. e.g. instead of `make -j $(nproc)` run `make -j2`. Failures due to memory exhaustion will typically but not always manifest as compiler crashes.
Generally we recommend performing what we refer to as a "pinned build" which ensures the compiler and boost version remain the same between builds of different mandel versions (mandel requires these versions remain the same otherwise its state needs to be repopulated from a portable snapshot).
#### Building Pinned Build Binary Packages
The pinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/main/README.md#pinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/main/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/main/README.md#step-3---build) before you build.
In the directory `<mandel src>/scripts` you will find the two scripts `install_deps.sh` and `pinned_build.sh`. If you haven't installed build dependencies then run `install_deps.sh`. Then run `pinned_build.sh <dependencies directory> <mandel build directory> <number of jobs>`.
The dependencies directory is where the script will pull the C++ dependencies that need to be built with the pinned compiler for building the pinned binaries for binary packaging.
The binary package will be produced in the mandel build directory that was supplied.
#### Manual (non "pinned") Build Instructions
The unpinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/main/README.md#unpinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/main/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/main/README.md#step-3---build) before you build.
<details>
<summary>Ubuntu 20.04 & 22.04 Build Instructions</summary>
Install required dependencies:
```
apt-get update && apt-get install \
build-essential \
cmake \
curl \
git \
libboost-all-dev \
libcurl4-openssl-dev \
libgmp-dev \
libssl-dev \
libusb-1.0-0-dev \
llvm-11-dev \
pkg-config
```
and perform the build:
```
git submodule update --init --recursive
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j $(nproc) package
```
</details>
<details>
<summary>Ubuntu 18.04 Build Instructions</summary>
Install required dependencies. You will need to build Boost from source on this distribution.
```
apt-get update && apt-get install \
build-essential \
cmake \
curl \
g++-8 \
git \
libcurl4-openssl-dev \
libgmp-dev \
libssl-dev \
libusb-1.0-0-dev \
llvm-7-dev \
pkg-config \
python3 \
zlib1g-dev
curl -L https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.tar.bz2 | tar jx && \
cd boost_1_79_0 && \
./bootstrap.sh --prefix=$HOME/boost1.79 && \
./b2 --with-iostreams --with-date_time --with-filesystem --with-system \
--with-program_options --with-chrono --with-test -j$(nproc) install && \
cd ..
```
and perform the build:
```
git submodule update --init --recursive
mkdir build
cd build
cmake -DCMAKE_C_COMPILER=gcc-8 -DCMAKE_CXX_COMPILER=g++-8 \
-DCMAKE_PREFIX_PATH="$HOME/boost1.79;/usr/lib/llvm-7/" -DCMAKE_BUILD_TYPE=Release .. \
make -j $(nproc) package
```
After building you may remove the `$HOME/boost1.79` directory, or you may keep it around until next time building the software.
</details>
### Running Tests
Documentation on available test suites and how to run them has moved [here](https://github.com/AntelopeIO/leap/blob/main/README.md#test).
When building from source it's recommended to run at least what we refer to as the "parallelizable tests". Not included by default in the "parallelizable tests" are the WASM spec tests which can add additional coverage and can also be run in parallel.
```
cd build
# "parallelizable tests": the minimum test set that should be run
ctest -j $(nproc) -LE _tests
# Also consider running the WASM spec tests for more coverage
ctest -j $(nproc) -L wasm_spec_tests
```
Some other tests are available and recommended but be aware they can be sensitive to other software running on the same host and they may **SIGKILL** other nodeos instances running on the host.
```
cd build
# These tests can't run in parallel but are recommended.
ctest -L "nonparallelizable_tests"
# These tests can't run in parallel. They also take a long time to run.
ctest -L "long_running_tests"
```
+3 -3
View File
@@ -10,9 +10,9 @@ The best way to install and use the Antelope software is to build it from source
Antelope currently supports the following operating systems:
1. Ubuntu 22.04 Jammy
2. Ubuntu 20.04 Focal
3. Ubuntu 18.04 Bionic
1. Ubuntu 18.04
2. Ubuntu 20.04
3. Ubuntu 22.04
[[info | Note]]
| It may be possible to build and install Antelope on other Unix-based operating systems. We gathered helpful information on the following page but please keep in mind that it is experimental and not officially supported.
+1
View File
@@ -13,6 +13,7 @@ For information on specific plugins, just select from the list below:
* [`db_size_api_plugin`](db_size_api_plugin/index.md)
* [`http_client_plugin`](http_client_plugin/index.md)
* [`http_plugin`](http_plugin/index.md)
* [`login_plugin`](login_plugin/index.md)
* [`net_api_plugin`](net_api_plugin/index.md)
* [`net_plugin`](net_plugin/index.md)
* [`producer_plugin`](producer_plugin/index.md)
@@ -0,0 +1,47 @@
## Description
The `login_plugin` supports the concept of applications authenticating with the Antelope blockchain. The `login_plugin` API allows an application to verify whether an account is allowed to sign in order to satisfy a specified authority.
## Usage
```console
# config.ini
plugin = eosio::login_plugin
[options]
```
```sh
# command-line
nodeos ... --plugin eosio::login_plugin [options]
```
## Options
These can be specified from both the `nodeos` command-line or the `config.ini` file:
```console
Config Options for eosio::login_plugin:
--max-login-requests arg (=1000000) The maximum number of pending login
requests
--max-login-timeout arg (=60) The maximum timeout for pending login
requests (in seconds)
```
## Dependencies
* [`chain_plugin`](../chain_plugin/index.md)
* [`http_plugin`](../http_plugin/index.md)
### Load Dependency Examples
```console
# config.ini
plugin = eosio::chain_plugin
[options]
plugin = eosio::http_plugin
[options]
```
```sh
# command-line
nodeos ... --plugin eosio::chain_plugin [options] \
--plugin eosio::http_plugin [options]
```
+5
View File
@@ -91,6 +91,11 @@ Config Options for eosio::wallet_plugin:
number of seconds of inactivity.
Activity is defined as any wallet
command e.g. list-wallets.
--yubihsm-url URL Override default URL of
http://localhost:12345 for connecting
to yubihsm-connector
--yubihsm-authkey key_num Enables YubiHSM support using given
Authkey
Application Config Options:
--plugin arg Plugin(s) to enable, may be specified
@@ -0,0 +1,73 @@
---
content_title: How To Attach a YubiHSM Hard Wallet
link_text: How To Attach a YubiHSM Hard Wallet
---
## Goal
Attach a YubiHSM as a hard wallet
## Before you begin
* Install the currently supported version of `keosd`
* Install YubiHSM2 Software Toolkit (YubiHSM2 SDK)
* Create an AuthKey with at least the following Capabilities:
* sign-ecdsa
* generate-asymmetric-key
* export-wrapped
* **Delete the default AuthKey**
[[warning | Security]]
| It is extremely important to create a new AuthKey and remove the default AuthKey before proceed to the following steps.
## Steps
### Configure `keosd`
There are two options to connect `keosd` to YubiHSM:
#### Using a YubiHSM connector
By default, `keosd` will connect to the YubiHSM connector on the default host and port. If a non-default URL is used, set the `--yubihsm-url` option or `yubihsm-url` in `config.ini` with the correct connector URL
#### Directly connect via USB
`keosd` also can directly connect to YubiHSM via USB protocol
If this option is used, set `keosd` startup option as the below:
```sh
--yubihsm-url=ysb://
```
### Start `keosd` with AuthKey:
```sh
--yubihsm-authkey Your_AuthKey_Object_Number
```
if a YubiHSM connector is used, check the YubiHSM connector is up and running by visiting YubiHSM URL:
http://YubiHSM_HOST:YubiHSM_PORT/connector/status ((Default HOST and Port: http://127.0.0.1:12345)
You should see something like this:
```console
status=OK
serial=*
version=2.0.0
pid=666
address=localhost
port=12345
```
### Unlock YubiHSM wallet with the password of AuthKey using the following option:
```sh
cleos wallet unlock -n YubiHSM --password YOUR_AUTHKEY_PASSWORD
```
After unlocking the wallet, you can use `cleos wallet` commands as usual. Beware as a part of security mechanism, some wallet subcommands, such as retrieve private keys, or remove a key, are not supported when a YubiHSM is used
+5
View File
@@ -0,0 +1,5 @@
---
content_title: Keosd How-to Guides
---
* [How to attach a YubiHSM hard wallet](how-to-attach-a-yubihsm-hard-wallet.md)
+7 -7
View File
@@ -4,8 +4,8 @@
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "LEAP"
PROJECT_NUMBER = "${DOXY_EOS_VERSION}"
PROJECT_NAME = "EOS.IO"
PROJECT_NUMBER = "EOSIO ${DOXY_EOS_VERSION}"
PROJECT_BRIEF =
PROJECT_LOGO = eos-logo.png
OUTPUT_DIRECTORY =
@@ -209,9 +209,9 @@ HTML_DYNAMIC_SECTIONS = NO
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = io.antelope
DOCSET_PUBLISHER_ID = com.eosnetwork
DOCSET_PUBLISHER_NAME = eosnetwork.com
DOCSET_BUNDLE_ID = io.eos
DOCSET_PUBLISHER_ID = one.block
DOCSET_PUBLISHER_NAME = block.one
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
@@ -221,14 +221,14 @@ BINARY_TOC = NO
TOC_EXPAND = NO
GENERATE_QHP = NO
QCH_FILE =
QHP_NAMESPACE = io.antelope
QHP_NAMESPACE = io.eos
QHP_VIRTUAL_FOLDER = doc
QHP_CUST_FILTER_NAME =
QHP_CUST_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS =
QHG_LOCATION =
GENERATE_ECLIPSEHELP = NO
ECLIPSE_DOC_ID = io.antelope
ECLIPSE_DOC_ID = io.eos
DISABLE_INDEX = NO
GENERATE_TREEVIEW = NO
ENUM_VALUES_PER_LINE = 4
+22
View File
@@ -26,3 +26,25 @@ set(ENABLE_PROFILE OFF CACHE BOOL "Enable for profile builds")
if(eos-vm IN_LIST EOSIO_WASM_RUNTIMES OR eos-vm-jit IN_LIST EOSIO_WASM_RUNTIMES)
add_subdirectory( eos-vm )
endif()
#yubihsm's openssl discovery is via pkg-config instead of find_package. Help it out on macOS otherwise openssl's pkgconfig
# files may not be found down in the /opt/homebrew/opt directory
if(APPLE)
get_filename_component(OPENSSL_LIB_PATH "${OPENSSL_CRYPTO_LIBRARY}" DIRECTORY)
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${OPENSSL_LIB_PATH}/pkgconfig")
endif()
set(ENABLE_STATIC ON)
set(CMAKE_MACOSX_RPATH OFF)
set(BUILD_ONLY_LIB ON CACHE BOOL "Library only build")
message(STATUS "Starting yubihsm configuration...")
add_subdirectory( yubihsm EXCLUDE_FROM_ALL )
target_compile_options(yubihsm_static PRIVATE -fno-lto -fcommon)
message(STATUS "yubihsm configuration complete")
get_property(_CTEST_CUSTOM_TESTS_IGNORE GLOBAL PROPERTY CTEST_CUSTOM_TESTS_IGNORE)
set_property(GLOBAL PROPERTY CTEST_CUSTOM_TESTS_IGNORE
"change_authkey import_ed decrypt_ec decrypt_rsa ssh logs generate_rsa import_ec echo\
yubico_otp wrap_data wrap info import_rsa import_authkey generate_hmac generate_ec\
attest pbkdf2 parsing ${_CTEST_CUSTOM_TESTS_IGNORE}")
add_subdirectory(prometheus)
+25 -55
View File
@@ -157,7 +157,6 @@ struct pending_state {
block_stage_type _block_stage;
controller::block_status _block_status = controller::block_status::incomplete;
std::optional<block_id_type> _producer_block_id;
controller::block_report _block_report{};
/** @pre _block_stage cannot hold completed_block alternative */
const pending_block_header_state& get_pending_block_header_state()const {
@@ -230,7 +229,7 @@ struct controller_impl {
protocol_feature_manager protocol_features;
controller::config conf;
const chain_id_type chain_id; // read by thread_pool threads, value will not be changed
bool replaying = false;
std::optional<fc::time_point> replay_head_time;
db_read_mode read_mode = db_read_mode::SPECULATIVE;
bool in_trx_requiring_checks = false; ///< if true, checks that are normally skipped on replay (e.g. auth checks) cannot be skipped
std::optional<fc::microseconds> subjective_cpu_leeway;
@@ -483,7 +482,8 @@ struct controller_impl {
}
auto blog_head = blog.head();
replaying = true;
auto blog_head_time = blog_head ? blog_head->timestamp.to_time_point() : fork_db.root()->header.timestamp.to_time_point();
replay_head_time = blog_head_time;
auto start_block_num = head->block_num + 1;
auto start = fc::time_point::now();
@@ -551,7 +551,7 @@ struct controller_impl {
ilog( "replayed ${n} blocks in ${duration} seconds, ${mspb} ms/block",
("n", head->block_num + 1 - start_block_num)("duration", (end-start).count()/1000000)
("mspb", ((end-start).count()/1000.0)/(head->block_num-start_block_num)) );
replaying = false;
replay_head_time.reset();
if( except_ptr ) {
std::rethrow_exception( except_ptr );
@@ -820,10 +820,7 @@ struct controller_impl {
});
}
void add_to_snapshot( const snapshot_writer_ptr& snapshot ) {
// clear in case the previous call to clear did not finish in time of deadline
clear_expired_input_transactions( fc::time_point::maximum() );
void add_to_snapshot( const snapshot_writer_ptr& snapshot ) const {
snapshot->write_section<chain_snapshot_header>([this]( auto &section ){
section.add_row(chain_snapshot_header(), db);
});
@@ -996,7 +993,7 @@ struct controller_impl {
);
}
sha256 calculate_integrity_hash() {
sha256 calculate_integrity_hash() const {
sha256::encoder enc;
auto hash_writer = std::make_shared<integrity_hash_snapshot_writer>(enc);
add_to_snapshot(hash_writer);
@@ -1255,7 +1252,6 @@ struct controller_impl {
uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time = false )
{ try {
auto start = fc::time_point::now();
const bool validating = !self.is_producing_block();
EOS_ASSERT( !validating || explicit_billed_cpu_time, transaction_exception, "validating requires explicit billing" );
@@ -1295,10 +1291,6 @@ struct controller_impl {
trace->scheduled = true;
trace->receipt = push_receipt( gtrx.trx_id, transaction_receipt::expired, billed_cpu_time_us, 0 ); // expire the transaction
trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta );
trace->elapsed = fc::time_point::now() - start;
pending->_block_report.total_cpu_usage_us += billed_cpu_time_us;
pending->_block_report.total_elapsed_time += trace->elapsed;
pending->_block_report.total_time += trace->elapsed;
emit( self.accepted_transaction, trx );
dmlog_applied_transaction(trace);
emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
@@ -1329,7 +1321,7 @@ struct controller_impl {
trace->error_code = controller::convert_exception_to_error_code( e );
trace->except = e;
trace->except_ptr = std::current_exception();
trace->elapsed = fc::time_point::now() - start;
trace->elapsed = fc::time_point::now() - trx_context.start;
if (auto dm_logger = get_deep_mind_logger()) {
dm_logger->on_fail_deferred();
@@ -1373,11 +1365,6 @@ struct controller_impl {
restore.cancel();
pending->_block_report.total_net_usage += trace->net_usage;
pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
pending->_block_report.total_elapsed_time += trace->elapsed;
pending->_block_report.total_time += fc::time_point::now() - start;
return trace;
} catch( const disallowed_transaction_extensions_bad_block_exception& ) {
throw;
@@ -1408,18 +1395,13 @@ struct controller_impl {
trace = error_trace;
if( !trace->except_ptr ) {
trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta );
trace->elapsed = fc::time_point::now() - start;
emit( self.accepted_transaction, trx );
dmlog_applied_transaction(trace);
emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
undo_session.squash();
pending->_block_report.total_net_usage += trace->net_usage;
if( trace->receipt ) pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
pending->_block_report.total_elapsed_time += trace->elapsed;
pending->_block_report.total_time += trace->elapsed;
return trace;
}
trace->elapsed = fc::time_point::now() - start;
trace->elapsed = fc::time_point::now() - trx_context.start;
}
// Only subjective OR hard failure logic below:
@@ -1466,11 +1448,6 @@ struct controller_impl {
emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
}
pending->_block_report.total_net_usage += trace->net_usage;
if( trace->receipt ) pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
pending->_block_report.total_elapsed_time += trace->elapsed;
pending->_block_report.total_time += fc::time_point::now() - start;
return trace;
} FC_CAPTURE_AND_RETHROW() } /// push_scheduled_transaction
@@ -1551,8 +1528,10 @@ struct controller_impl {
trx_context.init_for_implicit_trx();
trx_context.enforce_whiteblacklist = false;
} else {
bool skip_recording = replay_head_time && (time_point(trn.expiration) < *replay_head_time);
trx_context.init_for_input_trx( trx->packed_trx()->get_unprunable_size(),
trx->packed_trx()->get_prunable_size() );
trx->packed_trx()->get_prunable_size(),
skip_recording);
}
trx_context.delay = fc::seconds(trn.delay_sec);
@@ -1611,13 +1590,6 @@ struct controller_impl {
trx_context.squash();
}
if( !trx->read_only ) {
pending->_block_report.total_net_usage += trace->net_usage;
pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
pending->_block_report.total_elapsed_time += trace->elapsed;
pending->_block_report.total_time += fc::time_point::now() - start;
}
return trace;
} catch( const disallowed_transaction_extensions_bad_block_exception& ) {
throw;
@@ -1635,14 +1607,9 @@ struct controller_impl {
}
if (!trx->read_only) {
emit(self.accepted_transaction, trx);
dmlog_applied_transaction(trace);
emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));
pending->_block_report.total_net_usage += trace->net_usage;
if( trace->receipt ) pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
pending->_block_report.total_elapsed_time += trace->elapsed;
pending->_block_report.total_time += fc::time_point::now() - start;
emit(self.accepted_transaction, trx);
dmlog_applied_transaction(trace);
emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));
}
return trace;
@@ -1762,7 +1729,7 @@ struct controller_impl {
)
{
// Promote proposed schedule to pending schedule.
if( !replaying ) {
if( !replay_head_time ) {
ilog( "promoting proposed schedule (set in block ${proposed_num}) to pending; current block: ${n} lib: ${lib} schedule: ${schedule} ",
("proposed_num", *gpo.proposed_schedule_block_num)("n", pbhs.block_num)
("lib", pbhs.dpos_irreversible_blocknum)
@@ -2096,6 +2063,12 @@ struct controller_impl {
EOS_ASSERT( r == static_cast<const transaction_receipt_header&>(receipt),
block_validate_exception, "receipt does not match, ${lhs} != ${rhs}",
("lhs", r)("rhs", static_cast<const transaction_receipt_header&>(receipt)) );
if( trace ) {
br.total_net_usage += trace->net_usage;
if( trace->receipt ) br.total_cpu_usage_us += trace->receipt->cpu_usage_us;
br.total_elapsed_time += trace->elapsed;
}
}
finalize_block();
@@ -2116,7 +2089,6 @@ struct controller_impl {
// create completed_block with the existing block_state as we just verified it is the same as assembled_block
pending->_block_stage = completed_block{ bsp };
br = pending->_block_report; // copy before commit block destroys pending
commit_block(false);
br.total_time = fc::time_point::now() - start;
return;
@@ -2422,7 +2394,7 @@ struct controller_impl {
//Look for expired transactions in the deduplication list, and remove them.
auto& transaction_idx = db.get_mutable_index<transaction_multi_index>();
const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
auto now = self.is_building_block() ? self.pending_block_time() : self.head_block_time();
auto now = self.pending_block_time();
const auto total = dedupe_index.size();
uint32_t num_removed = 0;
while( (!dedupe_index.empty()) && ( now > fc::time_point(dedupe_index.begin()->expiration) ) ) {
@@ -2857,7 +2829,7 @@ void controller::start_block( block_timestamp_type when,
block_status::incomplete, std::optional<block_id_type>(), deadline );
}
block_state_ptr controller::finalize_block( block_report& br, const signer_callback_type& signer_callback ) {
block_state_ptr controller::finalize_block( const signer_callback_type& signer_callback ) {
validate_db_available_size();
my->finalize_block();
@@ -2878,8 +2850,6 @@ block_state_ptr controller::finalize_block( block_report& br, const signer_callb
my->pending->_block_stage = completed_block{ bsp };
br = my->pending->_block_report;
return bsp;
}
@@ -3134,11 +3104,11 @@ block_id_type controller::get_block_id_for_num( uint32_t block_num )const { try
return id;
} FC_CAPTURE_AND_RETHROW( (block_num) ) }
sha256 controller::calculate_integrity_hash() { try {
sha256 controller::calculate_integrity_hash()const { try {
return my->calculate_integrity_hash();
} FC_LOG_AND_RETHROW() }
void controller::write_snapshot( const snapshot_writer_ptr& snapshot ) {
void controller::write_snapshot( const snapshot_writer_ptr& snapshot ) const {
EOS_ASSERT( !my->pending, block_validate_exception, "cannot take a consistent snapshot with a pending block" );
return my->add_to_snapshot(snapshot);
}
@@ -164,19 +164,18 @@ namespace eosio { namespace chain {
fc::time_point block_deadline, fc::microseconds max_transaction_time,
uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time );
block_state_ptr finalize_block( const signer_callback_type& signer_callback );
void sign_block( const signer_callback_type& signer_callback );
void commit_block();
std::future<block_state_ptr> create_block_state_future( const block_id_type& id, const signed_block_ptr& b );
struct block_report {
size_t total_net_usage = 0;
size_t total_cpu_usage_us = 0;
fc::microseconds total_elapsed_time{};
fc::microseconds total_time{};
};
block_state_ptr finalize_block( block_report& br, const signer_callback_type& signer_callback );
void sign_block( const signer_callback_type& signer_callback );
void commit_block();
std::future<block_state_ptr> create_block_state_future( const block_id_type& id, const signed_block_ptr& b );
/**
* @param br returns statistics for block
* @param block_state_future provide from call to create_block_state_future
@@ -257,8 +256,8 @@ namespace eosio { namespace chain {
block_id_type get_block_id_for_num( uint32_t block_num )const;
sha256 calculate_integrity_hash();
void write_snapshot( const snapshot_writer_ptr& snapshot );
sha256 calculate_integrity_hash()const;
void write_snapshot( const snapshot_writer_ptr& snapshot )const;
bool sender_avoids_whitelist_blacklist_enforcement( account_name sender )const;
void check_actor_list( const flat_set<account_name>& actors )const;
@@ -45,7 +45,8 @@ namespace eosio { namespace chain {
void init_for_implicit_trx( uint64_t initial_net_usage = 0 );
void init_for_input_trx( uint64_t packed_trx_unprunable_size,
uint64_t packed_trx_prunable_size );
uint64_t packed_trx_prunable_size,
bool skip_recording);
void init_for_deferred_trx( fc::time_point published );
+4 -2
View File
@@ -234,7 +234,8 @@ namespace eosio { namespace chain {
}
void transaction_context::init_for_input_trx( uint64_t packed_trx_unprunable_size,
uint64_t packed_trx_prunable_size )
uint64_t packed_trx_prunable_size,
bool skip_recording )
{
const transaction& trx = packed_trx.get_transaction();
if( trx.transaction_extensions.size() > 0 ) {
@@ -271,7 +272,8 @@ namespace eosio { namespace chain {
validate_referenced_accounts( trx, enforce_whiteblacklist && control.is_producing_block() );
}
init( initial_net_usage);
record_transaction( packed_trx.id(), trx.expiration ); /// checks for dupes
if (!skip_recording)
record_transaction( packed_trx.id(), trx.expiration ); /// checks for dupes
}
void transaction_context::init_for_deferred_trx( fc::time_point p )
+21 -151
View File
@@ -3,7 +3,7 @@
// https://github.com/CLIUtils/CLI11
//
// This is a standalone header file generated by MakeSingleHeader.py in CLI11/scripts
// from: b19d133
// from: 1d3b0a7
//
// CLI11 2.2.0 Copyright (c) 2017-2022 University of Cincinnati, developed by Henry
// Schreiner under NSF AWARD 1414736. All rights reserved.
@@ -34,28 +34,28 @@
#pragma once
// Standard combined includes:
#include <iostream>
#include <sstream>
#include <iterator>
#include <memory>
#include <string>
#include <exception>
#include <map>
#include <limits>
#include <numeric>
#include <type_traits>
#include <fstream>
#include <functional>
#include <cstdint>
#include <vector>
#include <tuple>
#include <locale>
#include <algorithm>
#include <cmath>
#include <set>
#include <stdexcept>
#include <iomanip>
#include <memory>
#include <utility>
#include <functional>
#include <iterator>
#include <type_traits>
#include <vector>
#include <exception>
#include <cstdint>
#include <cmath>
#include <numeric>
#include <tuple>
#include <algorithm>
#include <stdexcept>
#include <set>
#include <iomanip>
#include <locale>
#include <limits>
#include <sstream>
#include <fstream>
#include <map>
#include <iostream>
#define CLI11_VERSION_MAJOR 2
@@ -9420,134 +9420,4 @@ inline std::string Formatter::make_option_usage(const Option *opt) const {
class LeapFormatter : public Formatter {
// pseudographics - to draw subcommand tree
const char* tree_line = u8"\u2502";
const char* tree_angle = u8"\u2514";
const char* tree_fork = u8"\u251C";
public:
LeapFormatter() : Formatter() {
// this gives better, more compact display
column_width(25);
}
LeapFormatter(const LeapFormatter&) = default;
LeapFormatter(LeapFormatter&&) = default;
/// This prints out all the subcommands
virtual std::string make_subcommands(const App* app, AppFormatMode mode) const {
std::stringstream out;
std::vector<const App*> subcommands = app->get_subcommands({});
// Make a list in definition order of the groups seen
std::vector<std::string> subcmd_groups_seen;
for(const App* com: subcommands) {
if(com->get_name().empty()) {
if(!com->get_group().empty()) {
out << make_expanded(com);
}
continue;
}
std::string group_key = com->get_group();
if(!group_key.empty() &&
std::find_if(subcmd_groups_seen.begin(), subcmd_groups_seen.end(), [&group_key](std::string a) {
return detail::to_lower(a) == detail::to_lower(group_key);
}) == subcmd_groups_seen.end())
subcmd_groups_seen.push_back(group_key);
}
// For each group, filter out and print subcommands
for(const std::string& group: subcmd_groups_seen) {
if(mode != AppFormatMode::SubCompact) {// do not show "Subcommands" header for nested tems in compact mode
out << "\n"
<< group << ":\n";
}
std::vector<const App*> subcommands_group = app->get_subcommands([&group](const App* sub_app) {
return detail::to_lower(sub_app->get_group()) == detail::to_lower(group);
});
for(const App* new_com: subcommands_group) {
if(new_com->get_name().empty())
continue;
std::string tree_symbol = (subcommands_group.back() == new_com ? tree_angle : tree_fork);
std::string line_symbol = (subcommands_group.back() == new_com ? "" : tree_line);
std::string subc_symbol = "";
const App* parent = app->get_parent();
if(parent != nullptr) {
std::vector<const App*> sc_group = parent->get_subcommands([&group](const App* sub_app) {
return detail::to_lower(sub_app->get_group()) == detail::to_lower(group);
});
if(sc_group.back() != app) {
subc_symbol = tree_line;
}
}
switch(mode) {
case AppFormatMode::All:
out << tree_symbol << new_com->help(new_com->get_name(), AppFormatMode::Sub);
out << "\n";
break;
case AppFormatMode::AllCompact:
out << tree_symbol << new_com->help(new_com->get_name(), AppFormatMode::SubCompact);
out << line_symbol;
out << "\n";
break;
case AppFormatMode::Normal:
case AppFormatMode::Sub:
out << make_subcommand(new_com);
break;
case AppFormatMode::SubCompact:
out << tree_symbol << make_expanded(new_com, mode);
break;
default:
throw HorribleError("Internal error: unknown help type requested");
}
}
}
return out.str();
}
/// This prints out a subcommand in help-all
virtual std::string make_expanded(const App* sub, AppFormatMode mode = AppFormatMode::Sub) const {
std::stringstream out;
std::string tmp;
std::string subc_symbol = " ";
if(mode == AppFormatMode::SubCompact) {
detail::format_help(out, sub->get_display_name(true), sub->get_description(), column_width_);
out << make_subcommands(sub, mode);
} else {
out << sub->get_display_name(true) << "\n";
out << make_description(sub);
if(sub->get_name().empty() && !sub->get_aliases().empty()) {
detail::format_aliases(out, sub->get_aliases(), column_width_ + 2);
}
out << make_positionals(sub);
out << make_groups(sub, mode);
out << make_subcommands(sub, mode);
}
// Drop blank spaces
tmp = detail::find_and_replace(out.str(), "\n\n", "\n");
tmp = tmp.substr(0, tmp.size() - 1);// Remove the final '\n'
//
auto group = sub->get_parent()->get_group();
std::vector<const App*> sc_group = sub->get_parent()->get_subcommands(
[&group](const App* sub_app) { return detail::to_lower(sub_app->get_group()) == detail::to_lower(group); });
if(sc_group.back() != sub) {
subc_symbol = tree_line;
}
// Indent all but the first line (the name)
return detail::find_and_replace(tmp, "\n", "\n" + subc_symbol + " ") + "\n";
}
};
} // namespace CLI
+3 -3
View File
@@ -29,9 +29,9 @@ target_include_directories(secp256k1
target_link_libraries(secp256k1 PRIVATE secp256k1-internal)
install( TARGETS secp256k1
RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} COMPONENT dev EXCLUDE_FROM_ALL
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL
RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} ${INSTALL_COMPONENT_ARGS}
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} ${INSTALL_COMPONENT_ARGS}
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} ${INSTALL_COMPONENT_ARGS}
)
add_executable(secp256k1-bench secp256k1/src/bench.c)
+20
View File
@@ -0,0 +1,20 @@
add_library(prometheus-core
prometheus-cpp/core/src/check_names.cc
prometheus-cpp/core/src/counter.cc
prometheus-cpp/core/src/detail/builder.cc
prometheus-cpp/core/src/detail/ckms_quantiles.cc
prometheus-cpp/core/src/detail/time_window_quantiles.cc
prometheus-cpp/core/src/detail/utils.cc
prometheus-cpp/core/src/family.cc
prometheus-cpp/core/src/gauge.cc
prometheus-cpp/core/src/histogram.cc
prometheus-cpp/core/src/info.cc
prometheus-cpp/core/src/registry.cc
prometheus-cpp/core/src/serializer.cc
prometheus-cpp/core/src/summary.cc
prometheus-cpp/core/src/text_serializer.cc
)
target_include_directories( prometheus-core PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/prometheus-cpp/core/include)
@@ -0,0 +1,3 @@
#pragma once
# define PROMETHEUS_CPP_CORE_EXPORT
# define PROMETHEUS_CPP_CORE_NO_EXPORT
@@ -0,0 +1 @@
3rdparty
@@ -0,0 +1,10 @@
build:asan --strip=never
build:asan --copt -fsanitize=address
build:asan --copt -DADDRESS_SANITIZER
build:asan --copt -O0
build:asan --copt -fno-omit-frame-pointer
build:asan --copt -g
build:asan --linkopt -fsanitize=address
build:asan --cc_output_directory_tag=asan
build:ssl --define=with_civetweb_ssl=true
@@ -0,0 +1,2 @@
BasedOnStyle: Google
DerivePointerAlignment: false
@@ -0,0 +1,61 @@
name: Bazel CI
on: [push, pull_request]
jobs:
build:
name: Bazel on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
include:
- os: macOS-latest
bazel_args: "--cxxopt=-std=c++14"
- os: ubuntu-latest
bazel_args: "--cxxopt=-std=c++14"
- os: windows-latest
bazel_args: "--cxxopt=/std:c++14"
steps:
- name: Checkout source
uses: actions/checkout@v3
- name: Generate German locale on Ubuntu
if: runner.os == 'Linux'
run: |
sudo apt-get remove -y --purge man-db # avoid time-consuming trigger
sudo apt-get update
sudo apt-get install -y locales
sudo locale-gen de_DE.UTF-8 # used by SerializerTest
- name: Install telegraf on Ubuntu
if: runner.os == 'Linux'
run: |
curl -sL https://repos.influxdata.com/influxdb.key | sudo apt-key add -
source /etc/lsb-release
echo "deb https://repos.influxdata.com/${DISTRIB_ID,,} ${DISTRIB_CODENAME} stable" | sudo tee /etc/apt/sources.list.d/influxdb.list
sudo apt-get update
sudo apt-get install -y telegraf
- name: Install telegraf on macOS
if: runner.os == 'macOS'
run: brew install telegraf
- name: Build with SSL
run: bazel build --config=ssl ${{ matrix.bazel_args }} //...
- name: Test with SSL
run: bazel test --config=ssl ${{ matrix.bazel_args }} --test_output=all //...
- name: Build
run: bazel build ${{ matrix.bazel_args }} //...
- name: Test
run: bazel test ${{ matrix.bazel_args }} --test_output=all //...
- name: Scraping Test
if: runner.os != 'Windows'
run: bazel test ${{ matrix.bazel_args }} --test_output=all //pull/tests/integration:scrape-test
- name: Benchmark
run: bazel run ${{ matrix.bazel_args }} -c opt //core/benchmarks
@@ -0,0 +1,131 @@
name: CMake CI
on: [push, pull_request]
jobs:
build:
name: CMake on ${{ matrix.os }} with ${{ matrix.dependencies }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macOS-latest, ubuntu-18.04, windows-2019]
dependencies: [submodule, vcpkg]
steps:
- name: Checkout source
uses: actions/checkout@v3
with:
submodules: ${{ matrix.dependencies == 'submodule' }}
- name: Mount vcpkg cache
if: matrix.dependencies == 'vcpkg'
uses: actions/cache@v2
with:
path: "~/.cache/vcpkg/archives"
key: vcpkg-${{ matrix.os }}
- name: Default to x64-windows vcpkg triplet
if: matrix.dependencies == 'vcpkg' && runner.os == 'Windows'
run: echo "VCPKG_DEFAULT_TRIPLET=x64-windows" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
- name: Install vcpkg dependencies
if: matrix.dependencies == 'vcpkg'
run: vcpkg install benchmark civetweb curl[core] gtest zlib
- name: Generate German locale on Ubuntu
if: runner.os == 'Linux'
run: |
sudo apt-get remove -y --purge man-db # avoid time-consuming trigger
sudo apt-get update
sudo apt-get install -y locales
sudo locale-gen de_DE.UTF-8 # used by SerializerTest
- name: Install ninja on Ubuntu
if: runner.os == 'Linux'
run: |
sudo apt-get install -y ninja-build
- name: Install ninja on macOS
if: runner.os == 'macOS'
run: brew install ninja
- name: "Configure for Unix with internal dependencies"
if: matrix.dependencies == 'submodule' && runner.os != 'Windows'
run: cmake -DUSE_THIRDPARTY_LIBRARIES=ON -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/_install -DENABLE_WARNINGS_AS_ERRORS=ON -DENABLE_COMPRESSION=OFF -DENABLE_PUSH=OFF -DCMAKE_DEBUG_POSTFIX=_d -DCMAKE_CONFIGURATION_TYPES='Release;Debug' -G"Ninja Multi-Config" -S ${{ github.workspace }} -B ${{ github.workspace }}/_build
- name: "Configure for Windows with internal dependencies"
if: matrix.dependencies == 'submodule' && runner.os == 'Windows'
run: cmake -DUSE_THIRDPARTY_LIBRARIES=ON -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/_install -DENABLE_WARNINGS_AS_ERRORS=ON -DENABLE_COMPRESSION=OFF -DENABLE_PUSH=OFF -DCMAKE_DEBUG_POSTFIX=_d -S ${{ github.workspace }} -B ${{ github.workspace }}/_build
- name: "Configure for Unix with vcpkg dependencies"
if: matrix.dependencies == 'vcpkg' && runner.os != 'Windows'
run: cmake -DUSE_THIRDPARTY_LIBRARIES=OFF -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/_install "-DCMAKE_TOOLCHAIN_FILE=${VCPKG_INSTALLATION_ROOT}/scripts/buildsystems/vcpkg.cmake" -DCMAKE_DEBUG_POSTFIX=_d -DCMAKE_CONFIGURATION_TYPES='Release;Debug' -G"Ninja Multi-Config" -S ${{ github.workspace }} -B ${{ github.workspace }}/_build
- name: "Configure for Windows with vcpkg dependencies"
if: matrix.dependencies == 'vcpkg' && runner.os == 'Windows'
run: cmake -DUSE_THIRDPARTY_LIBRARIES=OFF -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/_install "-DCMAKE_TOOLCHAIN_FILE=${Env:VCPKG_INSTALLATION_ROOT}\scripts\buildsystems\vcpkg.cmake" -DCMAKE_DEBUG_POSTFIX=_d -S ${{ github.workspace }} -B ${{ github.workspace }}/_build
- name: "Build Debug"
run: cmake --build ${{ github.workspace }}/_build --config Debug
- name: "Build Release"
run: cmake --build ${{ github.workspace }}/_build --config Release
- name: "Test Debug"
run: ctest -C Debug -V -LE Benchmark
working-directory: "${{ github.workspace }}/_build"
- name: "Test Release"
run: ctest -C Release -V -LE Benchmark
working-directory: "${{ github.workspace }}/_build"
- name: "Run Benchmark"
run: ctest -C Release -V -L Benchmark
working-directory: "${{ github.workspace }}/_build"
- name: "Install Debug"
run: cmake --install ${{ github.workspace }}/_build --config Debug
- name: "Install Release"
run: cmake --install ${{ github.workspace }}/_build --config Release
- name: "Configure CMake import for Unix with internal dependencies"
if: matrix.dependencies == 'submodule' && runner.os != 'Windows'
run: cmake -Dprometheus-cpp_DIR=${{ github.workspace }}/_install/lib/cmake/prometheus-cpp -DCMAKE_CONFIGURATION_TYPES='Release;Debug' -G"Ninja Multi-Config" -S ${{ github.workspace }}/cmake/project-import-cmake -B ${{ github.workspace }}/_import_cmake
- name: "Configure CMake import for Windows with internal dependencies"
if: matrix.dependencies == 'submodule' && runner.os == 'Windows'
run: cmake -Dprometheus-cpp_DIR=${{ github.workspace }}/_install/lib/cmake/prometheus-cpp -S ${{ github.workspace }}/cmake/project-import-cmake -B ${{ github.workspace }}/_import_cmake
- name: "Configure CMake import for Unix with vcpkg dependencies"
if: matrix.dependencies == 'vcpkg' && runner.os != 'Windows'
run: cmake -Dprometheus-cpp_DIR=${{ github.workspace }}/_install/lib/cmake/prometheus-cpp "-DCMAKE_TOOLCHAIN_FILE=${VCPKG_INSTALLATION_ROOT}/scripts/buildsystems/vcpkg.cmake" -DCMAKE_CONFIGURATION_TYPES='Release;Debug' -G"Ninja Multi-Config" -S ${{ github.workspace }}/cmake/project-import-cmake -B ${{ github.workspace }}/_import_cmake
- name: "Configure CMake import for Windows with vcpkg dependencies"
if: matrix.dependencies == 'vcpkg' && runner.os == 'Windows'
run: cmake -Dprometheus-cpp_DIR=${{ github.workspace }}/_install/lib/cmake/prometheus-cpp "-DCMAKE_TOOLCHAIN_FILE=${Env:VCPKG_INSTALLATION_ROOT}\scripts\buildsystems\vcpkg.cmake" -S ${{ github.workspace }}/cmake/project-import-cmake -B ${{ github.workspace }}/_import_cmake
- name: "Build CMake import Debug"
run: cmake --build ${{ github.workspace }}/_import_cmake --config Debug
- name: "Build CMake import Release"
run: cmake --build ${{ github.workspace }}/_import_cmake --config Release
- name: "Configure for Unix Shared Libs with internal dependencies"
if: matrix.dependencies == 'submodule' && runner.os != 'Windows'
run: cmake -DUSE_THIRDPARTY_LIBRARIES=ON -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/_install_shared -DENABLE_WARNINGS_AS_ERRORS=ON -DENABLE_COMPRESSION=OFF -DENABLE_PUSH=OFF -DCMAKE_DEBUG_POSTFIX=_d -GNinja -S ${{ github.workspace }} -B ${{ github.workspace }}/_build_shared
- name: "Build for Unix Shared Libs"
if: matrix.dependencies == 'submodule' && runner.os != 'Windows'
run: cmake --build ${{ github.workspace }}/_build_shared
- name: "Install for Unix Shared Libs"
if: matrix.dependencies == 'submodule' && runner.os != 'Windows'
run: cmake --install ${{ github.workspace }}/_build_shared
- name: "Configure pkg-config import for Unix"
if: matrix.dependencies == 'submodule' && runner.os != 'Windows'
run: cmake -DCMAKE_PREFIX_PATH=${{ github.workspace }}/_install_shared -GNinja -S ${{ github.workspace }}/cmake/project-import-pkgconfig -B ${{ github.workspace }}/_import_pkgconfig
- name: "Build pkg-config import for Unix"
if: matrix.dependencies == 'submodule' && runner.os != 'Windows'
run: cmake --build ${{ github.workspace }}/_import_pkgconfig
@@ -0,0 +1,60 @@
name: Coverage
on: [push, pull_request]
jobs:
build:
name: Code Coverage
runs-on: ubuntu-20.04
steps:
- name: Checkout source
uses: actions/checkout@v3
- name: Mount vcpkg cache
uses: actions/cache@v2
with:
path: "~/.cache/vcpkg/archives"
key: vcpkg-${{ runner.os }}
- name: Install vcpkg dependencies
run: vcpkg install benchmark civetweb curl[core] gtest zlib
- name: Generate German locale on Ubuntu
if: runner.os == 'Linux'
run: |
sudo apt-get remove -y --purge man-db # avoid time-consuming trigger
sudo apt-get update
sudo apt-get install -y locales
sudo locale-gen de_DE.UTF-8 # used by SerializerTest
- name: Install ninja on Ubuntu
if: runner.os == 'Linux'
run: |
sudo apt-get install -y ninja-build
- name: Install lcov
if: runner.os == 'Linux'
run: |
sudo apt-get install -y lcov
- name: "CMake Configure for Unix with vcpkg dependencies"
env:
CFLAGS: "--coverage"
CXXFLAGS: "--coverage"
LDFLAGS: "--coverage"
run: cmake -DUSE_THIRDPARTY_LIBRARIES=OFF "-DCMAKE_TOOLCHAIN_FILE=${VCPKG_INSTALLATION_ROOT}/scripts/buildsystems/vcpkg.cmake" -GNinja -S ${{ github.workspace }} -B ${{ github.workspace }}/_build
- name: Build
run: cmake --build ${{ github.workspace }}/_build
- name: Test
run: ctest -V -LE Benchmark
working-directory: "${{ github.workspace }}/_build"
- name: Run lcov
run: lcov --capture --directory "${{ github.workspace }}/_build" --output-file coverage.info --no-external --directory "${{ github.workspace }}" --exclude '*/tests/*'
- name: Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: coverage.info
@@ -0,0 +1,30 @@
name: Doxygen
on:
push:
branches:
- master
jobs:
build:
name: Code Coverage
runs-on: ubuntu-20.04
steps:
- name: Checkout source
uses: actions/checkout@v3
- name: Install doxygen
run: |
sudo apt-get remove -y --purge man-db # avoid time-consuming trigger
sudo apt-get update
sudo apt-get install -y doxygen graphviz
- name: Generate doxygen
run: doxygen
working-directory: "${{ github.workspace }}/doc"
- name: Deploy documentation
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
force_orphan: true
publish_dir: ./doc/html
@@ -0,0 +1,55 @@
name: Linting
on: [push, pull_request]
jobs:
iwyu:
name: Include What You Use
runs-on: ubuntu-latest
container:
image: debian:sid-slim
steps:
- name: Install dependencies
run: |
apt-get update
apt-get install -y --no-install-recommends ca-certificates clang-14 cmake git iwyu libbenchmark-dev libcurl4-openssl-dev ninja-build zlib1g-dev
- name: Checkout source
uses: actions/checkout@v3
with:
submodules: true
- name: "CMake Configure"
run: cmake -GNinja -DRUN_IWYU=ON -DCMAKE_C_COMPILER=clang-14 -DCMAKE_CXX_COMPILER=clang++-14 -S ${GITHUB_WORKSPACE} -B ${GITHUB_WORKSPACE}/_build
- name: Build
run: cmake --build ${GITHUB_WORKSPACE}/_build 2>&1 | tee ${GITHUB_WORKSPACE}/output.txt
- name: Check build output
run: if egrep -q 'should (add|remove) these lines' ${GITHUB_WORKSPACE}/output.txt; then exit 1; fi
#- name: "CMake Configure"
# run: cmake -GNinja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -S ${GITHUB_WORKSPACE} -B ${GITHUB_WORKSPACE}/_build
#- name: "Run IWYU"
# run: iwyu_tool -p ${GITHUB_WORKSPACE}/_build core push pull -- -Xiwyu --mapping_file=${GITHUB_WORKSPACE}/cmake/googletest.imp -Xiwyu --no_fwd_decls 2>&1 | tee ${{ github.workspace }}/output.txt
format:
name: Clang Format
runs-on: ubuntu-20.04
steps:
- name: Checkout source
uses: actions/checkout@v3
# clang-format comes pre-installed
# https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md
#- name: Install dependencies
# run: |
# sudo apt-get remove -y --purge man-db # avoid time-consuming trigger
# sudo apt-get update
# sudo apt-get install -y clang-format-12
- name: Run clang-format
run: find . -type f \( -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o -name '*.cxx' -o -name '*.o' -o -name '*.h' -o -name '*.hpp' -o -name '*.hxx' \) -exec clang-format-12 -style=file -i {} \;
- name: Check for changes
run: git diff --exit-code
@@ -0,0 +1,34 @@
on:
release:
types: [created]
name: Handle Release
jobs:
build:
name: Upload Release Asset
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
persist-credentials: false
submodules: true
- name: Create tarball including submodules
shell: bash
env:
PREFIX: prometheus-cpp-with-submodules
run: |
git archive --prefix "${PREFIX}/" -o "${PREFIX}.tar" HEAD
git submodule foreach --recursive "git archive --prefix=${PREFIX}/\$path/ --output=\$sha1.tar HEAD && tar --concatenate --file=$(pwd)/${PREFIX}.tar \$sha1.tar && rm \$sha1.tar"
gzip "${PREFIX}.tar"
# using the official actions/upload-release-asset action would be preferred but is blocked by
# https://github.com/actions/upload-release-asset/pull/41
- name: Upload the artifacts
uses: skx/github-action-publish-binaries@75ce5546020fc1848da842f40240f9fa03e7a3a8 # release-0.14
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
args: prometheus-cpp-with-submodules.tar.gz
@@ -0,0 +1,7 @@
/bazel-*
cmake-build-*/
_*/
.idea/
doc/html/
.vscode
build
@@ -0,0 +1,6 @@
[submodule "googletest"]
path = 3rdparty/googletest
url = https://github.com/google/googletest.git
[submodule "civetweb"]
path = 3rdparty/civetweb
url = https://github.com/civetweb/civetweb.git
@@ -0,0 +1,11 @@
package(default_visibility = ["//visibility:public"])
config_setting(
name = "windows",
values = {"cpu": "x64_windows"},
)
config_setting(
name = "windows_msvc",
values = {"cpu": "x64_windows_msvc"},
)
@@ -0,0 +1,193 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
if(POLICY CMP0091)
cmake_policy(SET CMP0091 NEW) # recognize CMAKE_MSVC_RUNTIME_LIBRARY
endif()
project(prometheus-cpp
VERSION 1.1.0
DESCRIPTION "Prometheus Client Library for Modern C++"
HOMEPAGE_URL "https://github.com/jupp0r/prometheus-cpp"
)
include(GenerateExportHeader)
include(GNUInstallDirs)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
option(BUILD_SHARED_LIBS "Build libraries as shared ones" OFF)
option(ENABLE_PULL "Build prometheus-cpp pull library" ON)
option(ENABLE_PUSH "Build prometheus-cpp push library" ON)
option(ENABLE_COMPRESSION "Enable gzip compression" ON)
option(ENABLE_TESTING "Build tests" ON)
option(USE_THIRDPARTY_LIBRARIES "Use 3rdParty submodules" ON)
option(THIRDPARTY_CIVETWEB_WITH_SSL "Enable SSL support for embedded civetweb source code")
option(OVERRIDE_CXX_STANDARD_FLAGS "Force building with -std=c++11 even if the CXXLFAGS are configured differently" ON)
option(GENERATE_PKGCONFIG "Generate and install pkg-config files" ${UNIX})
option(RUN_IWYU "Run include-what-you-use" OFF)
if(OVERRIDE_CXX_STANDARD_FLAGS)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_EXTENSIONS Off)
endif()
# Set default directory permissions until
# https://gitlab.kitware.com/cmake/cmake/issues/15163
# is fixed
set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
OWNER_READ
OWNER_WRITE
OWNER_EXECUTE
GROUP_READ
GROUP_EXECUTE
WORLD_READ
WORLD_EXECUTE)
# Put DLLs and binaries into same directory
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
# Hide things by default for shared libraries
if(BUILD_SHARED_LIBS)
set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN YES)
endif()
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads)
# include-what-you-use
if(RUN_IWYU)
find_program(IWYU_EXECUTABLE NAMES include-what-you-use iwyu)
if(NOT IWYU_EXECUTABLE)
message(FATAL_ERROR "Include-what-you-use not found")
endif()
set(IWYU_ARGS
"${IWYU_EXECUTABLE}"
"-Xiwyu" "--no_fwd_decls"
"-Xiwyu" "--mapping_file=${CMAKE_CURRENT_SOURCE_DIR}/cmake/googletest.imp"
)
set(CMAKE_C_INCLUDE_WHAT_YOU_USE ${IWYU_ARGS})
set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${IWYU_ARGS})
endif()
# check for required libatomic
include(CheckAtomic)
if(ENABLE_TESTING)
if(USE_THIRDPARTY_LIBRARIES)
find_package(googlemock-3rdparty CONFIG REQUIRED)
else()
find_package(GTest 1.8.1 CONFIG REQUIRED)
endif()
find_package(benchmark CONFIG)
enable_testing()
endif()
# build flags for CI system
if(ENABLE_WARNINGS_AS_ERRORS AND NOT MSVC)
add_compile_options(
$<$<AND:$<STREQUAL:$<COMPILE_LANGUAGE>,CXX>,$<CXX_COMPILER_ID:AppleClang>>:-Werror>
$<$<AND:$<STREQUAL:$<COMPILE_LANGUAGE>,CXX>,$<CXX_COMPILER_ID:AppleClang>>:-Wall>
$<$<AND:$<STREQUAL:$<COMPILE_LANGUAGE>,CXX>,$<CXX_COMPILER_ID:AppleClang>>:-Wextra>
$<$<AND:$<STREQUAL:$<COMPILE_LANGUAGE>,CXX>,$<CXX_COMPILER_ID:AppleClang>>:-pedantic-errors>
$<$<AND:$<STREQUAL:$<COMPILE_LANGUAGE>,CXX>,$<CXX_COMPILER_ID:GNU>>:-Werror>
$<$<AND:$<STREQUAL:$<COMPILE_LANGUAGE>,CXX>,$<CXX_COMPILER_ID:GNU>>:-Wall>
$<$<AND:$<STREQUAL:$<COMPILE_LANGUAGE>,CXX>,$<CXX_COMPILER_ID:GNU>>:-pedantic-errors>
)
endif()
# pkgconfig
if(GENERATE_PKGCONFIG)
# see https://github.com/jupp0r/prometheus-cpp/issues/587
if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
set(PROMETHEUS_CPP_PKGCONFIG_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
else()
set(PROMETHEUS_CPP_PKGCONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
endif()
if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
set(PROMETHEUS_CPP_PKGCONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
else()
set(PROMETHEUS_CPP_PKGCONFIG_LIBDIR "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
endif()
endif()
# prometheus-cpp
add_subdirectory(core)
if(ENABLE_PULL)
add_subdirectory(pull)
endif()
if(ENABLE_PUSH)
add_subdirectory(push)
endif()
# install
include(CMakePackageConfigHelpers)
install(
EXPORT ${PROJECT_NAME}-targets
NAMESPACE ${PROJECT_NAME}::
FILE ${PROJECT_NAME}-targets.cmake
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
)
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake.in"
${PROJECT_NAME}-config.cmake
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
NO_CHECK_REQUIRED_COMPONENTS_MACRO
PATH_VARS CMAKE_INSTALL_INCLUDEDIR
)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
)
# packaging
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(CPACK_PACKAGE_CONTACT "prometheus-cpp@@noreply.github.com")
set(CPACK_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}")
set(CPACK_PACKAGE_RELOCATABLE OFF)
set(CPACK_PACKAGE_VENDOR "The prometheus-cpp authors")
if(CMAKE_VERSION VERSION_LESS "3.12")
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
endif()
set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS ON)
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
set(CPACK_RPM_PACKAGE_AUTOREQPROV ON)
set(CPACK_RPM_FILE_NAME RPM-DEFAULT)
include(CPack)
endif()
# summary
include(FeatureSummary)
add_feature_info("Pull" "${ENABLE_PULL}" "support for pulling metrics")
add_feature_info("Push" "${ENABLE_PUSH}" "support for pushing metrics to a push-gateway")
add_feature_info("Compression" "${ENABLE_COMPRESSION}" "support for zlib compression of metrics")
add_feature_info("pkg-config" "${GENERATE_PKGCONFIG}" "generate pkg-config files")
add_feature_info("IYWU" "${RUN_IWYU}" "include-what-you-use")
feature_summary(WHAT ALL)
@@ -0,0 +1,25 @@
MIT License
Copyright (c) 2016-2021 Jupp Mueller
Copyright (c) 2017-2022 Gregor Jasny
And many contributors, see
https://github.com/jupp0r/prometheus-cpp/graphs/contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,382 @@
# Prometheus Client Library for Modern C++
[![CI Status](https://github.com/jupp0r/prometheus-cpp/workflows/Continuous%20Integration/badge.svg)](https://github.com/jupp0r/prometheus-cpp/actions?workflow=Continuous+Integration)
[![Travis Status](https://travis-ci.org/jupp0r/prometheus-cpp.svg?branch=master)](https://travis-ci.org/jupp0r/prometheus-cpp)
[![Coverage Status](https://coveralls.io/repos/github/jupp0r/prometheus-cpp/badge.svg?branch=master)](https://coveralls.io/github/jupp0r/prometheus-cpp?branch=master)
[![Coverity Scan](https://scan.coverity.com/projects/10567/badge.svg)](https://scan.coverity.com/projects/jupp0r-prometheus-cpp)
This library aims to enable
[Metrics-Driven Development](https://sookocheff.com/post/mdd/mdd/) for
C++ services. It implements the
[Prometheus Data Model](https://prometheus.io/docs/concepts/data_model/),
a powerful abstraction on which to collect and expose metrics. We
offer the possibility for metrics to be collected by Prometheus, but
other push/pull collections can be added as plugins.
## Usage
See https://jupp0r.github.io/prometheus-cpp for more detailed interface documentation.
``` c++
#include <prometheus/counter.h>
#include <prometheus/exposer.h>
#include <prometheus/registry.h>
#include <array>
#include <chrono>
#include <cstdlib>
#include <memory>
#include <string>
#include <thread>
int main() {
using namespace prometheus;
// create an http server running on port 8080
Exposer exposer{"127.0.0.1:8080"};
// create a metrics registry
// @note it's the users responsibility to keep the object alive
auto registry = std::make_shared<Registry>();
// add a new counter family to the registry (families combine values with the
// same name, but distinct label dimensions)
//
// @note please follow the metric-naming best-practices:
// https://prometheus.io/docs/practices/naming/
auto& packet_counter = BuildCounter()
.Name("observed_packets_total")
.Help("Number of observed packets")
.Register(*registry);
// add and remember dimensional data, incrementing those is very cheap
auto& tcp_rx_counter =
packet_counter.Add({{"protocol", "tcp"}, {"direction", "rx"}});
auto& tcp_tx_counter =
packet_counter.Add({{"protocol", "tcp"}, {"direction", "tx"}});
auto& udp_rx_counter =
packet_counter.Add({{"protocol", "udp"}, {"direction", "rx"}});
auto& udp_tx_counter =
packet_counter.Add({{"protocol", "udp"}, {"direction", "tx"}});
// add a counter whose dimensional data is not known at compile time
// nevertheless dimensional values should only occur in low cardinality:
// https://prometheus.io/docs/practices/naming/#labels
auto& http_requests_counter = BuildCounter()
.Name("http_requests_total")
.Help("Number of HTTP requests")
.Register(*registry);
// ask the exposer to scrape the registry on incoming HTTP requests
exposer.RegisterCollectable(registry);
for (;;) {
std::this_thread::sleep_for(std::chrono::seconds(1));
const auto random_value = std::rand();
if (random_value & 1) tcp_rx_counter.Increment();
if (random_value & 2) tcp_tx_counter.Increment();
if (random_value & 4) udp_rx_counter.Increment();
if (random_value & 8) udp_tx_counter.Increment();
const std::array<std::string, 4> methods = {"GET", "PUT", "POST", "HEAD"};
auto method = methods.at(random_value % methods.size());
// dynamically calling Family<T>.Add() works but is slow and should be
// avoided
http_requests_counter.Add({{"method", method}}).Increment();
}
return 0;
}
```
## Requirements
Using `prometheus-cpp` requires a C++11 compliant compiler. It has been successfully tested with GNU GCC 7.4 on Ubuntu Bionic (18.04) and Visual Studio 2017 (but Visual Studio 2015 should work, too).
## Building
There are two supported ways to build
`prometheus-cpp` - [CMake](https://cmake.org)
and [bazel](https://bazel.io). Both are tested in CI and should work
on master and for all releases.
In case these instructions don't work for you, looking at
the [GitHub Workflows](.github/workflows) might help.
### via CMake
For CMake builds don't forget to fetch the submodules first. Please note that
[zlib](https://zlib.net/) and [libcurl](https://curl.se/) are not provided by
the included submodules. In the example below their usage is disabled.
Then build as usual.
``` shell
# fetch third-party dependencies
git submodule init
git submodule update
mkdir _build
cd _build
# run cmake
cmake .. -DBUILD_SHARED_LIBS=ON -DENABLE_PUSH=OFF -DENABLE_COMPRESSION=OFF
# build
cmake --build . --parallel 4
# run tests
ctest -V
# install the libraries and headers
cmake --install .
```
### via Bazel
Install [bazel](https://www.bazel.io). Bazel makes it easy to add
this repo to your project as a dependency. Just add the following
to your `WORKSPACE`:
```python
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file")
http_archive(
name = "com_github_jupp0r_prometheus_cpp",
strip_prefix = "prometheus-cpp-master",
urls = ["https://github.com/jupp0r/prometheus-cpp/archive/master.zip"],
)
load("@com_github_jupp0r_prometheus_cpp//bazel:repositories.bzl", "prometheus_cpp_repositories")
prometheus_cpp_repositories()
```
Then, you can reference this library in your own `BUILD` file, as
demonstrated with the sample server included in this repository:
```python
cc_binary(
name = "sample_server",
srcs = ["sample_server.cc"],
deps = ["@com_github_jupp0r_prometheus_cpp//pull"],
)
```
When you call `prometheus_cpp_repositories()` in your `WORKSPACE` file,
you load the following dependencies, if they do not exist yet, into your project:
* `civetweb` for [Civetweb](https://github.com/civetweb/civetweb)
* `com_google_googletest` for [Google Test](https://github.com/google/googletest)
* `com_github_google_benchmark` for [Google Benchmark](https://github.com/google/benchmark)
* `com_github_curl` for [curl](https://curl.haxx.se/)
* `net_zlib_zlib` for [zlib](http://www.zlib.net/)
The list of dependencies is also available from file [repositories.bzl](bazel/repositories.bzl).
## Packaging
By configuring CPack you can generate an installer like a
Debian package (.deb) or RPM (.rpm) for the static or dynamic
libraries so they can be easily installed on
other systems.
Please refer to the [CPack](https://cmake.org/cmake/help/latest/module/CPack.html)
documentation for all available generators and their
configuration options.
To generate a Debian package you could follow these steps:
``` shell
# fetch third-party dependencies
git submodule update --init
# run cmake
cmake -B_build -DCPACK_GENERATOR=DEB -DBUILD_SHARED_LIBS=ON # or OFF for static libraries
# build and package
cmake --build _build --target package --parallel $(nproc)
```
This will place an appropriately named .deb in the
`_build` folder. To build a RPM package set the `CPACK_GENERATOR`
variable to `RPM`.
## Consuming the installed project
### CMake
Consuming prometheus-cpp via CMake is the preferred way because all the dependencies
between the three prometheus-cpp libraries are handled correctly.
The `cmake/project-import` directory contains an
example project and minimal [CMakeLists.txt](cmake/project-import-cmake/CMakeLists.txt).
### vcpkg
The [vcpkg](https://github.com/microsoft/vcpkg) package manager contains a
prometheus-cpp port which has been tested on Linux, macOS, and Windows.
### Conan
[Conan](https://conan.io/) package manager contains prometheus-cpp package as well
in [ConanCenter](https://conan.io/center/prometheus-cpp) repository
### Plain Makefiles
When manually linking prometheus-cpp the library order matters. The needed
libraries depend on the individual use case but the following should work for the pull metrics approach:
```
-lprometheus-cpp-pull -lprometheus-cpp-core -lz
```
For the push-workflow please try:
```
-lprometheus-cpp-push -lprometheus-cpp-core -lcurl -lz
```
## Contributing
Please adhere to the [Google C++ Style
Guide](https://google.github.io/styleguide/cppguide.html). Make sure
to clang-format your patches before opening a PR. Also make sure to
adhere to [these commit message
guidelines](https://chris.beams.io/posts/git-commit/).
You can check out this repo and build the library using
``` bash
bazel build //... # build everything
bazel build //core //pull # build just the libraries
```
Run the unit tests using
```
bazel test //...
```
There is also an integration test that
uses [telegraf](https://github.com/influxdata/telegraf) to scrape a
sample server. With telegraf installed, it can be run using
```
bazel test //pull/tests/integration:scrape-test
```
## Benchmarks
There's a benchmark suite you can run:
```
bazel run -c opt //core/benchmarks
INFO: Analysed target //core/benchmarks:benchmarks (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //core/benchmarks:benchmarks up-to-date:
bazel-bin/core/benchmarks/benchmarks
INFO: Elapsed time: 0.356s, Critical Path: 0.01s, Remote (0.00% of the time): [queue: 0.00%, setup: 0.00%, process: 0.00%]
INFO: 0 processes.
INFO: Build completed successfully, 1 total action
INFO: Build completed successfully, 1 total action
2018-11-30 15:13:14
Run on (4 X 2200 MHz CPU s)
CPU Caches:
L1 Data 32K (x2)
L1 Instruction 32K (x2)
L2 Unified 262K (x2)
L3 Unified 4194K (x1)
-----------------------------------------------------------------------------------
Benchmark Time CPU Iterations
-----------------------------------------------------------------------------------
BM_Counter_Increment 13 ns 12 ns 55616469
BM_Counter_Collect 7 ns 7 ns 99823170
BM_Gauge_Increment 12 ns 12 ns 51511873
BM_Gauge_Decrement 12 ns 12 ns 56831098
BM_Gauge_SetToCurrentTime 184 ns 183 ns 3928964
BM_Gauge_Collect 6 ns 6 ns 117223478
BM_Histogram_Observe/0 134 ns 124 ns 5665310
BM_Histogram_Observe/1 122 ns 120 ns 5937185
BM_Histogram_Observe/8 137 ns 135 ns 4652863
BM_Histogram_Observe/64 143 ns 143 ns 4835957
BM_Histogram_Observe/512 259 ns 257 ns 2334750
BM_Histogram_Observe/4096 1545 ns 1393 ns 620754
BM_Histogram_Collect/0 103 ns 102 ns 5654829
BM_Histogram_Collect/1 100 ns 100 ns 7015153
BM_Histogram_Collect/8 608 ns 601 ns 1149652
BM_Histogram_Collect/64 1438 ns 1427 ns 515236
BM_Histogram_Collect/512 5178 ns 5159 ns 114619
BM_Histogram_Collect/4096 33527 ns 33280 ns 20785
BM_Registry_CreateFamily 320 ns 316 ns 2021567
BM_Registry_CreateCounter/0 128 ns 128 ns 5487140
BM_Registry_CreateCounter/1 2066 ns 2058 ns 386002
BM_Registry_CreateCounter/8 7672 ns 7634 ns 91328
BM_Registry_CreateCounter/64 63270 ns 62761 ns 10780
BM_Registry_CreateCounter/512 560714 ns 558328 ns 1176
BM_Registry_CreateCounter/4096 18672798 ns 18383000 ns 35
BM_Summary_Observe/0/iterations:262144 9351 ns 9305 ns 262144
BM_Summary_Observe/1/iterations:262144 9242 ns 9169 ns 262144
BM_Summary_Observe/8/iterations:262144 14344 ns 14195 ns 262144
BM_Summary_Observe/64/iterations:262144 19176 ns 18950 ns 262144
BM_Summary_Collect/0/0 31 ns 30 ns 24873766
BM_Summary_Collect/1/0 166 ns 166 ns 4266706
BM_Summary_Collect/8/0 1040 ns 1036 ns 660527
BM_Summary_Collect/64/0 4529 ns 4489 ns 155600
BM_Summary_Collect/0/1 28 ns 28 ns 24866697
BM_Summary_Collect/1/1 190 ns 188 ns 3930354
BM_Summary_Collect/8/1 1372 ns 1355 ns 535779
BM_Summary_Collect/64/1 9901 ns 9822 ns 64632
BM_Summary_Collect/0/8 29 ns 29 ns 24922651
BM_Summary_Collect/1/8 217 ns 215 ns 3278381
BM_Summary_Collect/8/8 2275 ns 2256 ns 282503
BM_Summary_Collect/64/8 56790 ns 55804 ns 13878
BM_Summary_Collect/0/64 32 ns 31 ns 22548350
BM_Summary_Collect/1/64 395 ns 389 ns 1817073
BM_Summary_Collect/8/64 10187 ns 10064 ns 71928
BM_Summary_Collect/64/64 374835 ns 373560 ns 1812
BM_Summary_Collect/0/512 28 ns 28 ns 25234228
BM_Summary_Collect/1/512 1710 ns 1639 ns 802285
BM_Summary_Collect/8/512 50355 ns 49335 ns 15975
BM_Summary_Collect/64/512 2520972 ns 2493417 ns 295
BM_Summary_Collect/0/4096 31 ns 31 ns 24059034
BM_Summary_Collect/1/4096 2719 ns 2698 ns 286186
BM_Summary_Collect/8/4096 121689 ns 119995 ns 5647
BM_Summary_Collect/64/4096 5660131 ns 5587634 ns 134
BM_Summary_Collect/0/32768 29 ns 29 ns 22217567
BM_Summary_Collect/1/32768 4344 ns 4294 ns 138135
BM_Summary_Collect/8/32768 331563 ns 326403 ns 2017
BM_Summary_Collect/64/32768 16363553 ns 16038182 ns 44
BM_Summary_Collect/0/262144 27 ns 27 ns 23923036
BM_Summary_Collect/1/262144 10457 ns 10332 ns 67690
BM_Summary_Collect/8/262144 930434 ns 869234 ns 792
BM_Summary_Collect/64/262144 39217069 ns 39054846 ns 13
BM_Summary_Observe_Common/iterations:262144 5587 ns 5557 ns 262144
BM_Summary_Collect_Common/0 676 ns 673 ns 1054630
BM_Summary_Collect_Common/1 709 ns 705 ns 990659
BM_Summary_Collect_Common/8 1030 ns 1025 ns 685649
BM_Summary_Collect_Common/64 2066 ns 2055 ns 339969
BM_Summary_Collect_Common/512 5754 ns 5248 ns 156895
BM_Summary_Collect_Common/4096 23894 ns 23292 ns 31096
BM_Summary_Collect_Common/32768 49831 ns 49292 ns 13492
BM_Summary_Collect_Common/262144 128723 ns 126987 ns 5579
```
## Project Status
Stable and used in production.
Parts of the library are instrumented by itself
(bytes scraped, number of scrapes, scrape request latencies). There
is a working [example](pull/tests/integration/sample_server.cc) that's
scraped by telegraf as part of integration tests.
## FAQ
### What scrape formats do you support
Only the [Prometheus Text Exposition
Format](https://github.com/prometheus/docs/blob/master/content/docs/instrumenting/exposition_formats.md#text-format-details).
Support for the protobuf format was removed because it's been removed
from Prometheus 2.0.
## License
MIT
@@ -0,0 +1,5 @@
workspace(name = "com_github_jupp0r_prometheus_cpp")
load("//bazel:repositories.bzl", "prometheus_cpp_repositories")
prometheus_cpp_repositories()
@@ -0,0 +1,7 @@
exports_files(
glob([
"*.BUILD",
"*.tpl",
]),
visibility = ["//visibility:public"],
)
@@ -0,0 +1,103 @@
licenses(["notice"]) # MIT license
config_setting(
name = "osx",
constraint_values = [
"@bazel_tools//platforms:osx",
],
)
config_setting(
name = "windows",
constraint_values = [
"@bazel_tools//platforms:windows",
],
)
config_setting(
name = "with_ssl",
define_values = {
"with_civetweb_ssl": "true",
},
visibility = ["//visibility:public"],
)
COPTS = [
"-DUSE_IPV6",
"-DNDEBUG",
"-DNO_CGI",
"-DNO_CACHING",
"-DNO_FILES",
"-UDEBUG",
] + select({
":with_ssl": [
"-DOPENSSL_API_1_1",
"-DNO_SSL_DL",
],
"@//conditions:default": [
"-DNO_SSL",
],
})
DEPS = select({
":with_ssl": [
"@boringssl//:crypto",
"@boringssl//:ssl",
],
"@//conditions:default": [],
})
cc_library(
name = "libcivetweb",
srcs = [
"src/civetweb.c",
"src/response.inl",
],
hdrs = [
"include/civetweb.h",
],
copts = COPTS,
includes = [
"include",
],
linkopts = select({
":windows": [],
"//conditions:default": ["-lpthread"],
}) + select({
":osx": [],
":windows": [],
"//conditions:default": ["-lrt"],
}),
textual_hdrs = [
"src/md5.inl",
"src/handle_form.inl",
],
visibility = ["//visibility:public"],
deps = DEPS,
)
cc_library(
name = "civetweb",
srcs = [
"src/CivetServer.cpp",
],
hdrs = [
"include/CivetServer.h",
],
copts = COPTS,
includes = [
"include",
],
linkopts = select({
":windows": [],
"//conditions:default": ["-lpthread"],
}) + select({
":osx": [],
":windows": [],
"//conditions:default": ["-lrt"],
}),
visibility = ["//visibility:public"],
deps = [
":libcivetweb",
],
)
@@ -0,0 +1,72 @@
# Copyright 2017, OpenCensus Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# copied from: https://github.com/census-instrumentation/opencensus-cpp/blob/master/WORKSPACE
licenses(["notice"]) # MIT/X derivative license
load("@com_github_jupp0r_prometheus_cpp//bazel:curl.bzl", "CURL_COPTS")
package(features = ["no_copts_tokenization"])
config_setting(
name = "windows",
constraint_values = [
"@bazel_tools//platforms:windows",
],
visibility = ["//visibility:private"],
)
config_setting(
name = "osx",
constraint_values = [
"@bazel_tools//platforms:osx",
],
visibility = ["//visibility:private"],
)
cc_library(
name = "curl",
srcs = glob([
"lib/**/*.c",
]),
hdrs = glob([
"include/curl/*.h",
"lib/**/*.h",
]),
copts = CURL_COPTS + [
'-DOS="os"',
],
defines = ["CURL_STATICLIB"],
includes = [
"include/",
"lib/",
],
linkopts = select({
"//:windows": [
"-DEFAULTLIB:ws2_32.lib",
"-DEFAULTLIB:advapi32.lib",
"-DEFAULTLIB:crypt32.lib",
"-DEFAULTLIB:Normaliz.lib",
],
"//:osx": [
"-framework SystemConfiguration",
"-lpthread",
],
"//conditions:default": [
"-lpthread",
],
}),
visibility = ["//visibility:public"],
)
@@ -0,0 +1,201 @@
# Copyright 2018, OpenCensus Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Compiler options for building libcurl.
# copied from: https://github.com/census-instrumentation/opencensus-cpp/blob/master/opencensus/curl.bzl
BASE_CURL_COPTS = [
# Disable everything else except HTTP protocol.
"-DHTTP_ONLY=1",
"-DENABLE_IPV6=1",
"-DGETHOSTNAME_TYPE_ARG2=size_t",
"-DGETSERVBYPORT_R_ARGS=6",
"-DGETSERVBYPORT_R_BUFSIZE=4096",
"-DHAVE_ALARM=1",
"-DHAVE_ALLOCA_H=1",
"-DHAVE_ARPA_INET_H=1",
"-DHAVE_ARPA_TFTP_H=1",
"-DHAVE_ASSERT_H=1",
"-DHAVE_BASENAME=1",
"-DHAVE_BOOL_T=1",
"-DHAVE_CLOCK_GETTIME_MONOTONIC=1",
"-DHAVE_CONNECT=1",
"-DHAVE_DLFCN_H=1",
"-DHAVE_ENGINE_LOAD_BUILTIN_ENGINES=1",
"-DHAVE_ERRNO_H=1",
"-DHAVE_FCNTL=1",
"-DHAVE_FCNTL_H=1",
"-DHAVE_FCNTL_O_NONBLOCK=1",
"-DHAVE_FDOPEN=1",
"-DHAVE_FREEADDRINFO=1",
"-DHAVE_FREEIFADDRS=1",
"-DHAVE_FSETXATTR=1",
"-DHAVE_FSETXATTR_5=1",
"-DHAVE_FTRUNCATE=1",
"-DHAVE_GAI_STRERROR=1",
"-DHAVE_GETADDRINFO=1",
"-DHAVE_GETADDRINFO_THREADSAFE=1",
"-DHAVE_GETEUID=1",
"-DHAVE_GETHOSTBYADDR=1",
"-DHAVE_GETHOSTBYADDR_R=1",
"-DHAVE_GETHOSTBYADDR_R_8=1",
"-DHAVE_GETHOSTBYNAME=1",
"-DHAVE_GETHOSTBYNAME_R=1",
"-DHAVE_GETHOSTBYNAME_R_6=1",
"-DHAVE_GETHOSTNAME=1",
"-DHAVE_GETIFADDRS=1",
"-DHAVE_GETPPID=1",
"-DHAVE_GETPWUID=1",
"-DHAVE_GETPWUID_R=1",
"-DHAVE_GETRLIMIT=1",
"-DHAVE_GETSERVBYPORT_R=1",
"-DHAVE_GETTIMEOFDAY=1",
"-DHAVE_GMTIME_R=1",
"-DHAVE_IFADDRS_H=1",
"-DHAVE_IF_NAMETOINDEX=1",
"-DHAVE_INET_NTOP=1",
"-DHAVE_INET_PTON=1",
"-DHAVE_INTTYPES_H=1",
"-DHAVE_IOCTL=1",
"-DHAVE_IOCTL_FIONBIO=1",
"-DHAVE_IOCTL_SIOCGIFADDR=1",
"-DHAVE_LIBGEN_H=1",
"-DHAVE_LL=1",
"-DHAVE_LOCALE_H=1",
"-DHAVE_LOCALTIME_R=1",
"-DHAVE_LONGLONG=1",
"-DHAVE_MALLOC_H=1",
"-DHAVE_MEMORY_H=1",
"-DHAVE_NETDB_H=1",
"-DHAVE_NETINET_IN_H=1",
"-DHAVE_NETINET_TCP_H=1",
"-DHAVE_NET_IF_H=1",
"-DHAVE_PIPE=1",
"-DHAVE_POLL=1",
"-DHAVE_POLL_FINE=1",
"-DHAVE_POLL_H=1",
"-DHAVE_POSIX_STRERROR_R=1",
"-DHAVE_PTHREAD_H=1",
"-DHAVE_PWD_H=1",
"-DHAVE_RECV=1",
"-DHAVE_SA_FAMILY_T=1",
"-DHAVE_SELECT=1",
"-DHAVE_SEND=1",
"-DHAVE_SETJMP_H=1",
"-DHAVE_SETLOCALE=1",
"-DHAVE_SETRLIMIT=1",
"-DHAVE_SETSOCKOPT=1",
"-DHAVE_SGTTY_H=1",
"-DHAVE_SIGACTION=1",
"-DHAVE_SIGINTERRUPT=1",
"-DHAVE_SIGNAL=1",
"-DHAVE_SIGNAL_H=1",
"-DHAVE_SIGSETJMP=1",
"-DHAVE_SIG_ATOMIC_T=1",
"-DHAVE_SOCKADDR_IN6_SIN6_SCOPE_ID=1",
"-DHAVE_SOCKET=1",
"-DHAVE_SOCKETPAIR=1",
"-DHAVE_STDBOOL_H=1",
"-DHAVE_STDINT_H=1",
"-DHAVE_STDIO_H=1",
"-DHAVE_STDLIB_H=1",
"-DHAVE_STRCASECMP=1",
"-DHAVE_STRDUP=1",
"-DHAVE_STRERROR_R=1",
"-DHAVE_STRINGS_H=1",
"-DHAVE_STRING_H=1",
"-DHAVE_STRNCASECMP=1",
"-DHAVE_STRSTR=1",
"-DHAVE_STRTOK_R=1",
"-DHAVE_STRTOLL=1",
"-DHAVE_STRUCT_SOCKADDR_STORAGE=1",
"-DHAVE_STRUCT_TIMEVAL=1",
"-DHAVE_SYS_IOCTL_H=1",
"-DHAVE_SYS_PARAM_H=1",
"-DHAVE_SYS_POLL_H=1",
"-DHAVE_SYS_RESOURCE_H=1",
"-DHAVE_SYS_SELECT_H=1",
"-DHAVE_SYS_SOCKET_H=1",
"-DHAVE_SYS_STAT_H=1",
"-DHAVE_SYS_TIME_H=1",
"-DHAVE_SYS_TYPES_H=1",
"-DHAVE_SYS_UIO_H=1",
"-DHAVE_SYS_UN_H=1",
"-DHAVE_SYS_WAIT_H=1",
"-DHAVE_SYS_XATTR_H=1",
"-DHAVE_TERMIOS_H=1",
"-DHAVE_TERMIO_H=1",
"-DHAVE_TIME_H=1",
"-DHAVE_UNISTD_H=1",
"-DHAVE_UTIME=1",
"-DHAVE_UTIMES=1",
"-DHAVE_UTIME_H=1",
"-DHAVE_VARIADIC_MACROS_C99=1",
"-DHAVE_VARIADIC_MACROS_GCC=1",
"-DHAVE_WRITABLE_ARGV=1",
"-DHAVE_WRITEV=1",
"-DRECV_TYPE_ARG1=int",
"-DRECV_TYPE_ARG2=void*",
"-DRECV_TYPE_ARG3=size_t",
"-DRECV_TYPE_ARG4=int",
"-DRECV_TYPE_RETV=ssize_t",
"-DSELECT_QUAL_ARG5=",
"-DSELECT_TYPE_ARG1=int",
"-DSELECT_TYPE_ARG234=fd_set*",
"-DSELECT_TYPE_RETV=int",
"-DSEND_QUAL_ARG2=const",
"-DSEND_TYPE_ARG1=int",
"-DSEND_TYPE_ARG2=void*",
"-DSEND_TYPE_ARG3=size_t",
"-DSEND_TYPE_ARG4=int",
"-DSEND_TYPE_RETV=ssize_t",
"-DSIZEOF_CURL_OFF_T=8",
"-DSIZEOF_INT=4",
"-DSIZEOF_LONG=8",
"-DSIZEOF_OFF_T=8",
"-DSIZEOF_SHORT=2",
"-DSIZEOF_SIZE_T=8",
"-DSIZEOF_TIME_T=8",
"-DSTDC_HEADERS=1",
"-DSTRERROR_R_TYPE_ARG3=size_t",
"-DTIME_WITH_SYS_TIME=1",
"-DUSE_THREADS_POSIX=1",
"-DUSE_UNIX_SOCKETS=1",
# Extra defines needed by curl
"-DBUILDING_LIBCURL",
"-DCURL_HIDDEN_SYMBOLS",
]
LINUX_CURL_COPTS = [
"-DHAVE_LINUX_TCP_H=1",
"-DHAVE_MSG_NOSIGNAL=1",
]
CURL_COPTS = select({
"//:windows": [
# Disable everything else except HTTP protocol.
"/DHTTP_ONLY=1",
"/DCURL_STATICLIB",
"/DWIN32",
"/DBUILDING_LIBCURL",
"/DUSE_WIN32_IDN",
"/DWANT_IDN_PROTOTYPES",
"/DUSE_IPV6",
"/DUSE_WINDOWS_SSPI",
"/DUSE_SCHANNEL",
],
"//:osx": BASE_CURL_COPTS,
"//conditions:default": BASE_CURL_COPTS + LINUX_CURL_COPTS,
})
@@ -0,0 +1,4 @@
#pragma once
#define {BASE_NAME}_EXPORT
#define {BASE_NAME}_NO_EXPORT
@@ -0,0 +1,21 @@
def _generate_dummy_export_header_impl(ctx):
ctx.actions.expand_template(
template = ctx.file._template,
output = ctx.outputs.header_file,
substitutions = {
"{BASE_NAME}": ctx.attr.basename,
},
)
generate_dummy_export_header = rule(
attrs = {
"basename": attr.string(mandatory = True),
"header": attr.string(mandatory = True),
"_template": attr.label(
allow_single_file = True,
default = Label("@com_github_jupp0r_prometheus_cpp//bazel:dummy_export.h.tpl"),
),
},
implementation = _generate_dummy_export_header_impl,
outputs = {"header_file": "%{header}"},
)
@@ -0,0 +1,72 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
def prometheus_cpp_repositories():
maybe(
http_archive,
name = "civetweb",
strip_prefix = "civetweb-1.15",
sha256 = "90a533422944ab327a4fbb9969f0845d0dba05354f9cacce3a5005fa59f593b9",
urls = [
"https://github.com/civetweb/civetweb/archive/v1.15.tar.gz",
],
build_file = "@com_github_jupp0r_prometheus_cpp//bazel:civetweb.BUILD",
)
maybe(
http_archive,
name = "com_google_googletest",
sha256 = "b4870bf121ff7795ba20d20bcdd8627b8e088f2d1dab299a031c1034eddc93d5",
strip_prefix = "googletest-release-1.11.0",
urls = [
"https://github.com/google/googletest/archive/release-1.11.0.tar.gz",
],
)
maybe(
http_archive,
name = "com_github_curl",
sha256 = "3c6893d38d054d4e378267166858698899e9d87258e8ff1419d020c395384535",
strip_prefix = "curl-7.84.0",
urls = [
"https://github.com/curl/curl/releases/download/curl-7_84_0/curl-7.84.0.tar.gz",
"https://curl.haxx.se/download/curl-7.84.0.tar.gz",
],
build_file = "@com_github_jupp0r_prometheus_cpp//bazel:curl.BUILD",
)
maybe(
http_archive,
name = "com_github_google_benchmark",
sha256 = "6132883bc8c9b0df5375b16ab520fac1a85dc9e4cf5be59480448ece74b278d4",
strip_prefix = "benchmark-1.6.1",
urls = [
"https://github.com/google/benchmark/archive/v1.6.1.tar.gz",
],
)
maybe(
http_archive,
name = "net_zlib_zlib",
sha256 = "91844808532e5ce316b3c010929493c0244f3d37593afd6de04f71821d5136d9",
strip_prefix = "zlib-1.2.12",
urls = [
"https://mirror.bazel.build/zlib.net/zlib-1.2.12.tar.gz",
"https://zlib.net/zlib-1.2.12.tar.gz",
"https://storage.googleapis.com/bazel-mirror/zlib.net/zlib-1.2.12.tar.gz",
],
build_file = "@com_github_jupp0r_prometheus_cpp//bazel:zlib.BUILD",
)
maybe(
http_archive,
name = "boringssl",
# Use github mirror instead of https://boringssl.googlesource.com/boringssl
# to obtain a boringssl archive with consistent sha256
sha256 = "534fa658bd845fd974b50b10f444d392dfd0d93768c4a51b61263fd37d851c40",
strip_prefix = "boringssl-b9232f9e27e5668bc0414879dcdedb2a59ea75f2",
urls = [
"https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/boringssl/archive/b9232f9e27e5668bc0414879dcdedb2a59ea75f2.tar.gz",
"https://github.com/google/boringssl/archive/b9232f9e27e5668bc0414879dcdedb2a59ea75f2.tar.gz",
],
)
@@ -0,0 +1,16 @@
# copied from: https://github.com/bazelbuild/bazel/blob/master/third_party/zlib/BUILD
licenses(["notice"]) # BSD/MIT-like license (for zlib)
cc_library(
name = "z",
srcs = glob(["*.c"]),
hdrs = glob(["*.h"]),
# Use -Dverbose=-1 to turn off zlib's trace logging. (bazelbuild/bazel#3280)
copts = [
"-w",
"-Dverbose=-1",
],
includes = ["."],
visibility = ["//visibility:public"],
)
@@ -0,0 +1,5 @@
[
{ include: [ "@<gmock/.*>", private, "<gmock/gmock.h>", public ] },
{ include: [ "@<gtest/.*>", private, "<gtest/gtest.h>", public ] },
{ include: [ "@<bits/this_thread_sleep.h>", private, "<thread>", public ]}
]
@@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(prometheus-cpp-import)
find_package(prometheus-cpp CONFIG REQUIRED)
if(PROMETHEUS_CPP_ENABLE_PUSH)
add_executable(sample-client sample_client.cc)
target_link_libraries(sample-client PRIVATE prometheus-cpp::push)
endif()
if(PROMETHEUS_CPP_ENABLE_PULL)
add_executable(sample-server sample_server.cc)
target_link_libraries(sample-server PRIVATE prometheus-cpp::pull)
endif()
@@ -0,0 +1 @@
../../push/tests/integration/sample_client.cc
@@ -0,0 +1 @@
../../pull/tests/integration/sample_server.cc
@@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(prometheus-cpp-import)
set(CMAKE_CXX_STANDARD 14)
find_package(PkgConfig REQUIRED)
pkg_check_modules(PROMETHEUS_CPP_CORE REQUIRED prometheus-cpp-core)
pkg_check_modules(PROMETHEUS_CPP_PUSH IMPORTED_TARGET prometheus-cpp-push)
pkg_check_modules(PROMETHEUS_CPP_PULL IMPORTED_TARGET prometheus-cpp-pull)
if(PROMETHEUS_CPP_PUSH_FOUND)
add_executable(sample-client sample_client.cc)
target_link_libraries(sample-client PRIVATE PkgConfig::PROMETHEUS_CPP_PUSH)
endif()
if(PROMETHEUS_CPP_PULL_FOUND)
add_executable(sample-server sample_server.cc)
target_link_libraries(sample-server PRIVATE PkgConfig::PROMETHEUS_CPP_PULL)
endif()
@@ -0,0 +1 @@
../../push/tests/integration/sample_client.cc
@@ -0,0 +1 @@
../../pull/tests/integration/sample_server.cc
@@ -0,0 +1,34 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
set_and_check(prometheus-cpp_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
set(PROMETHEUS_CPP_ENABLE_PULL @ENABLE_PULL@)
set(PROMETHEUS_CPP_ENABLE_PUSH @ENABLE_PUSH@)
set(PROMETHEUS_CPP_USE_COMPRESSION @ENABLE_COMPRESSION@)
set(PROMETHEUS_CPP_USE_THIRDPARTY_LIBRARIES @USE_THIRDPARTY_LIBRARIES@)
set(PROMETHEUS_CPP_THIRDPARTY_CIVETWEB_WITH_SSL @THIRDPARTY_CIVETWEB_WITH_SSL@)
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_dependency(Threads)
unset(CMAKE_THREAD_PREFER_PTHREAD)
if(PROMETHEUS_CPP_ENABLE_PULL)
if(PROMETHEUS_CPP_USE_THIRDPARTY_LIBRARIES)
if(PROMETHEUS_CPP_THIRDPARTY_CIVETWEB_WITH_SSL)
find_dependency(OpenSSL)
endif()
else()
find_dependency(civetweb)
endif()
endif()
if(PROMETHEUS_CPP_ENABLE_PULL AND PROMETHEUS_CPP_USE_COMPRESSION)
find_dependency(ZLIB)
endif()
if(PROMETHEUS_CPP_ENABLE_PUSH)
find_dependency(CURL)
endif()
include("${CMAKE_CURRENT_LIST_DIR}/prometheus-cpp-targets.cmake")
@@ -0,0 +1,14 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
includedir=@PROMETHEUS_CPP_PKGCONFIG_INCLUDEDIR@
libdir=@PROMETHEUS_CPP_PKGCONFIG_LIBDIR@
Name: @PROJECT_NAME@-core
Description: @PROJECT_DESCRIPTION@
URL: @PROJECT_HOMEPAGE_URL@
Version: @PROJECT_VERSION@
Requires:
Requires.private: @PKGCONFIG_REQUIRES@
Cflags: -I${includedir}
Libs: -L${libdir} -l@PROJECT_NAME@-core
Libs.private: @CMAKE_THREAD_LIBS_INIT@ @PKGCONFIG_LIBS@
@@ -0,0 +1,14 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
includedir=@PROMETHEUS_CPP_PKGCONFIG_INCLUDEDIR@
libdir=@PROMETHEUS_CPP_PKGCONFIG_LIBDIR@
Name: @PROJECT_NAME@-pull
Description: @PROJECT_DESCRIPTION@
URL: @PROJECT_HOMEPAGE_URL@
Version: @PROJECT_VERSION@
Requires: @PROJECT_NAME@-core
Requires.private: @PKGCONFIG_REQUIRES@
Cflags: -I${includedir}
Libs: -L${libdir} -l@PROJECT_NAME@-pull
Libs.private: @CMAKE_THREAD_LIBS_INIT@ @PKGCONFIG_LIBS@
@@ -0,0 +1,14 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
includedir=@PROMETHEUS_CPP_PKGCONFIG_INCLUDEDIR@
libdir=@PROMETHEUS_CPP_PKGCONFIG_LIBDIR@
Name: @PROJECT_NAME@-push
Description: @PROJECT_DESCRIPTION@
URL: @PROJECT_HOMEPAGE_URL@
Version: @PROJECT_VERSION@
Requires: @PROJECT_NAME@-core
Requires.private: @PKGCONFIG_REQUIRES@
Cflags: -I${includedir}
Libs: -L${libdir} -l@PROJECT_NAME@-push
Libs.private: @CMAKE_THREAD_LIBS_INIT@ @PKGCONFIG_LIBS@
@@ -0,0 +1,20 @@
load("//bazel:export_header.bzl", "generate_dummy_export_header")
generate_dummy_export_header(
name = "export_header",
basename = "PROMETHEUS_CPP_CORE",
header = "include/prometheus/detail/core_export.h",
)
cc_library(
name = "core",
srcs = glob([
"src/**/*.cc",
"src/**/*.h",
]),
hdrs = glob(
["include/**/*.h"],
) + [":export_header"],
strip_include_prefix = "include",
visibility = ["//visibility:public"],
)
@@ -0,0 +1,100 @@
add_library(core
src/check_names.cc
src/counter.cc
src/detail/builder.cc
src/detail/ckms_quantiles.cc
src/detail/time_window_quantiles.cc
src/detail/utils.cc
src/family.cc
src/gauge.cc
src/histogram.cc
src/info.cc
src/registry.cc
src/serializer.cc
src/summary.cc
src/text_serializer.cc
)
add_library(${PROJECT_NAME}::core ALIAS core)
target_compile_features(core
PUBLIC
cxx_std_14
)
target_link_libraries(core
PRIVATE
Threads::Threads
$<$<AND:$<BOOL:UNIX>,$<NOT:$<BOOL:APPLE>>>:rt>
)
if(HAVE_CXX_LIBATOMIC)
# the exported library config must use libatomic unconditionally
# (the HAVE_CXX_LIBATOMIC variable should not leak into the target config)
target_link_libraries(core PUBLIC atomic)
endif()
target_include_directories(core
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
)
set_target_properties(core
PROPERTIES
OUTPUT_NAME ${PROJECT_NAME}-core
DEFINE_SYMBOL PROMETHEUS_CPP_CORE_EXPORTS
VERSION "${PROJECT_VERSION}"
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
)
generate_export_header(core
BASE_NAME ${PROJECT_NAME}-core
EXPORT_FILE_NAME include/prometheus/detail/core_export.h
)
install(
TARGETS core
EXPORT ${PROJECT_NAME}-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(
DIRECTORY include/ ${CMAKE_CURRENT_BINARY_DIR}/include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
if(GENERATE_PKGCONFIG)
set(PKGCONFIG_LIBS)
set(PKGCONFIG_REQUIRES)
if(HAVE_CXX_LIBATOMIC)
string(APPEND PKGCONFIG_LIBS " -latomic")
endif()
configure_file(
${PROJECT_SOURCE_DIR}/cmake/prometheus-cpp-core.pc.in
${CMAKE_CURRENT_BINARY_DIR}/prometheus-cpp-core.pc
@ONLY
)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/prometheus-cpp-core.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
unset(PKGCONFIG_LIBS)
unset(PKGCONFIG_REQUIRES)
endif()
if(ENABLE_TESTING)
add_subdirectory(tests)
endif()
if(benchmark_FOUND)
add_subdirectory(benchmarks)
endif()
@@ -0,0 +1,12 @@
cc_binary(
name = "benchmarks",
srcs = glob([
"*.cc",
"*.h",
]),
linkstatic = True,
deps = [
"//core",
"@com_github_google_benchmark//:benchmark",
],
)
@@ -0,0 +1,28 @@
add_executable(benchmarks
main.cc
benchmark_helpers.cc
benchmark_helpers.h
counter_bench.cc
gauge_bench.cc
histogram_bench.cc
info_bench.cc
registry_bench.cc
summary_bench.cc
)
target_link_libraries(benchmarks
PRIVATE
${PROJECT_NAME}::core
benchmark::benchmark
)
add_test(
NAME benchmarks
COMMAND benchmarks
)
set_property(
TEST benchmarks
APPEND PROPERTY LABELS Benchmark
)
@@ -0,0 +1,26 @@
#include "benchmark_helpers.h"
#include <algorithm>
#include <cstdlib>
#include <map>
std::string GenerateRandomString(std::size_t length) {
auto randchar = []() -> char {
const char charset[] = "abcdefghijklmnopqrstuvwxyz";
const std::size_t max_index = (sizeof(charset) - 1);
return charset[rand() % max_index];
};
std::string str(length, 0);
std::generate_n(str.begin(), length, randchar);
return str;
}
prometheus::Labels GenerateRandomLabels(std::size_t number_of_pairs) {
const auto label_character_count = 10;
auto label_pairs = prometheus::Labels{};
for (std::size_t i = 0; i < number_of_pairs; i++) {
label_pairs.insert({GenerateRandomString(label_character_count),
GenerateRandomString(label_character_count)});
}
return label_pairs;
}
@@ -0,0 +1,9 @@
#pragma once
#include <cstddef>
#include <string>
#include "prometheus/labels.h"
std::string GenerateRandomString(std::size_t length);
prometheus::Labels GenerateRandomLabels(std::size_t number_of_labels);
@@ -0,0 +1,33 @@
#include <benchmark/benchmark.h>
#include "prometheus/counter.h"
#include "prometheus/family.h"
#include "prometheus/registry.h"
static void BM_Counter_Increment(benchmark::State& state) {
using prometheus::BuildCounter;
using prometheus::Counter;
using prometheus::Registry;
Registry registry;
auto& counter_family =
BuildCounter().Name("benchmark_counter").Help("").Register(registry);
auto& counter = counter_family.Add({});
while (state.KeepRunning()) counter.Increment();
}
BENCHMARK(BM_Counter_Increment);
static void BM_Counter_Collect(benchmark::State& state) {
using prometheus::BuildCounter;
using prometheus::Counter;
using prometheus::Registry;
Registry registry;
auto& counter_family =
BuildCounter().Name("benchmark_counter").Help("").Register(registry);
auto& counter = counter_family.Add({});
while (state.KeepRunning()) {
benchmark::DoNotOptimize(counter.Collect());
};
}
BENCHMARK(BM_Counter_Collect);
@@ -0,0 +1,59 @@
#include <benchmark/benchmark.h>
#include "prometheus/family.h"
#include "prometheus/gauge.h"
#include "prometheus/registry.h"
static void BM_Gauge_Increment(benchmark::State& state) {
using prometheus::BuildGauge;
using prometheus::Gauge;
using prometheus::Registry;
Registry registry;
auto& gauge_family =
BuildGauge().Name("benchmark_gauge").Help("").Register(registry);
auto& gauge = gauge_family.Add({});
while (state.KeepRunning()) gauge.Increment(2);
}
BENCHMARK(BM_Gauge_Increment);
static void BM_Gauge_Decrement(benchmark::State& state) {
using prometheus::BuildGauge;
using prometheus::Gauge;
using prometheus::Registry;
Registry registry;
auto& gauge_family =
BuildGauge().Name("benchmark_gauge").Help("").Register(registry);
auto& gauge = gauge_family.Add({});
while (state.KeepRunning()) gauge.Decrement(2);
}
BENCHMARK(BM_Gauge_Decrement);
static void BM_Gauge_SetToCurrentTime(benchmark::State& state) {
using prometheus::BuildGauge;
using prometheus::Gauge;
using prometheus::Registry;
Registry registry;
auto& gauge_family =
BuildGauge().Name("benchmark_gauge").Help("").Register(registry);
auto& gauge = gauge_family.Add({});
while (state.KeepRunning()) gauge.SetToCurrentTime();
}
BENCHMARK(BM_Gauge_SetToCurrentTime);
static void BM_Gauge_Collect(benchmark::State& state) {
using prometheus::BuildGauge;
using prometheus::Gauge;
using prometheus::Registry;
Registry registry;
auto& gauge_family =
BuildGauge().Name("benchmark_gauge").Help("").Register(registry);
auto& gauge = gauge_family.Add({});
while (state.KeepRunning()) {
benchmark::DoNotOptimize(gauge.Collect());
};
}
BENCHMARK(BM_Gauge_Collect);
@@ -0,0 +1,70 @@
#include <benchmark/benchmark.h>
#include <chrono>
#include <cstdint>
#include <random>
#include <vector>
#include "prometheus/family.h"
#include "prometheus/histogram.h"
#include "prometheus/registry.h"
using prometheus::Histogram;
static Histogram::BucketBoundaries CreateLinearBuckets(std::int64_t start,
std::int64_t end,
std::int64_t step) {
auto bucket_boundaries = Histogram::BucketBoundaries{};
for (auto i = start; i < end; i += step) {
bucket_boundaries.push_back(i);
}
return bucket_boundaries;
}
static void BM_Histogram_Observe(benchmark::State& state) {
using prometheus::BuildHistogram;
using prometheus::Histogram;
using prometheus::Registry;
const auto number_of_buckets = state.range(0);
Registry registry;
auto& histogram_family =
BuildHistogram().Name("benchmark_histogram").Help("").Register(registry);
auto bucket_boundaries = CreateLinearBuckets(0, number_of_buckets - 1, 1);
auto& histogram = histogram_family.Add({}, bucket_boundaries);
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> d(0, number_of_buckets);
while (state.KeepRunning()) {
auto observation = d(gen);
auto start = std::chrono::high_resolution_clock::now();
histogram.Observe(observation);
auto end = std::chrono::high_resolution_clock::now();
auto elapsed_seconds =
std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
state.SetIterationTime(elapsed_seconds.count());
}
}
BENCHMARK(BM_Histogram_Observe)->Range(0, 4096);
static void BM_Histogram_Collect(benchmark::State& state) {
using prometheus::BuildHistogram;
using prometheus::Histogram;
using prometheus::Registry;
const auto number_of_buckets = state.range(0);
Registry registry;
auto& histogram_family =
BuildHistogram().Name("benchmark_histogram").Help("").Register(registry);
auto bucket_boundaries = CreateLinearBuckets(0, number_of_buckets - 1, 1);
auto& histogram = histogram_family.Add({}, bucket_boundaries);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(histogram.Collect());
}
}
BENCHMARK(BM_Histogram_Collect)->Range(0, 4096);
@@ -0,0 +1,20 @@
#include <benchmark/benchmark.h>
#include "prometheus/family.h"
#include "prometheus/info.h"
#include "prometheus/registry.h"
static void BM_Info_Collect(benchmark::State& state) {
using prometheus::BuildInfo;
using prometheus::Info;
using prometheus::Registry;
Registry registry;
auto& info_family =
BuildInfo().Name("benchmark_info").Help("").Register(registry);
auto& info = info_family.Add({});
while (state.KeepRunning()) {
benchmark::DoNotOptimize(info.Collect());
};
}
BENCHMARK(BM_Info_Collect);
@@ -0,0 +1,3 @@
#include <benchmark/benchmark.h>
BENCHMARK_MAIN();
@@ -0,0 +1,44 @@
#include <benchmark/benchmark.h>
#include <chrono>
#include "benchmark_helpers.h"
#include "prometheus/counter.h"
#include "prometheus/family.h"
#include "prometheus/registry.h"
static void BM_Registry_CreateFamily(benchmark::State& state) {
using prometheus::BuildCounter;
using prometheus::Counter;
using prometheus::Registry;
Registry registry;
while (state.KeepRunning())
BuildCounter().Name("benchmark_counter").Help("").Register(registry);
}
BENCHMARK(BM_Registry_CreateFamily);
static void BM_Registry_CreateCounter(benchmark::State& state) {
using prometheus::BuildCounter;
using prometheus::Counter;
using prometheus::Registry;
Registry registry;
auto& counter_family = BuildCounter()
.Labels(GenerateRandomLabels(10))
.Name("benchmark_counter")
.Help("")
.Register(registry);
while (state.KeepRunning()) {
auto labels = GenerateRandomLabels(state.range(0));
auto start = std::chrono::high_resolution_clock::now();
counter_family.Add(labels);
auto end = std::chrono::high_resolution_clock::now();
auto elapsed_seconds =
std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
state.SetIterationTime(elapsed_seconds.count());
}
}
BENCHMARK(BM_Registry_CreateCounter)->Range(0, 4096);
@@ -0,0 +1,139 @@
#include <benchmark/benchmark.h>
#include <algorithm>
#include <chrono>
#include <cmath>
#include <random>
#include <vector>
#include "prometheus/family.h"
#include "prometheus/registry.h"
#include "prometheus/summary.h"
using prometheus::Summary;
static const auto ITERATIONS = 262144;
static Summary::Quantiles CreateLinearQuantiles(int count) {
static auto generator = [](double x) {
static auto exp = [](double x) {
static const double A = 2;
return 1 - std::exp(-A * x);
};
return exp(x) / exp(1);
};
auto quantiles = Summary::Quantiles{};
for (auto i = 0; i < count; ++i) {
quantiles.emplace_back(generator(double(i) / count), 0.01);
}
return quantiles;
}
static void BM_Summary_Observe(benchmark::State& state) {
using prometheus::BuildSummary;
using prometheus::Registry;
using prometheus::Summary;
const auto number_of_quantiles = state.range(0);
Registry registry;
auto& summary_family =
BuildSummary().Name("benchmark_summary").Help("").Register(registry);
auto quantiles = CreateLinearQuantiles(number_of_quantiles);
auto& summary = summary_family.Add({}, quantiles);
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> d(0, 100);
while (state.KeepRunning()) {
auto observation = d(gen);
auto start = std::chrono::high_resolution_clock::now();
summary.Observe(observation);
auto end = std::chrono::high_resolution_clock::now();
auto elapsed_seconds =
std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
state.SetIterationTime(elapsed_seconds.count());
}
}
BENCHMARK(BM_Summary_Observe)->Range(0, 64)->Iterations(ITERATIONS);
static void BM_Summary_Collect(benchmark::State& state) {
using prometheus::BuildSummary;
using prometheus::Registry;
using prometheus::Summary;
const auto number_of_quantiles = state.range(0);
const auto number_of_entries = state.range(1);
Registry registry;
auto& summary_family =
BuildSummary().Name("benchmark_summary").Help("").Register(registry);
auto quantiles = CreateLinearQuantiles(number_of_quantiles);
auto& summary = summary_family.Add({}, quantiles);
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> d(0, 100);
for (auto i = 1; i <= number_of_entries; ++i) summary.Observe(d(gen));
while (state.KeepRunning()) {
benchmark::DoNotOptimize(summary.Collect());
}
}
BENCHMARK(BM_Summary_Collect)->RangePair(0, 64, 0, ITERATIONS);
static void BM_Summary_Observe_Common(benchmark::State& state) {
using prometheus::BuildSummary;
using prometheus::Registry;
using prometheus::Summary;
Registry registry;
auto& summary_family =
BuildSummary().Name("benchmark_summary").Help("").Register(registry);
auto& summary = summary_family.Add(
{}, Summary::Quantiles{
{0.5, 0.05}, {0.9, 0.01}, {0.95, 0.005}, {0.99, 0.001}});
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> d(0, 100);
while (state.KeepRunning()) {
auto observation = d(gen);
auto start = std::chrono::high_resolution_clock::now();
summary.Observe(observation);
auto end = std::chrono::high_resolution_clock::now();
auto elapsed_seconds =
std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
state.SetIterationTime(elapsed_seconds.count());
}
}
BENCHMARK(BM_Summary_Observe_Common)->Iterations(ITERATIONS);
static void BM_Summary_Collect_Common(benchmark::State& state) {
using prometheus::BuildSummary;
using prometheus::Registry;
using prometheus::Summary;
const auto number_of_entries = state.range(0);
Registry registry;
auto& summary_family =
BuildSummary().Name("benchmark_summary").Help("").Register(registry);
auto& summary = summary_family.Add(
{}, Summary::Quantiles{
{0.5, 0.05}, {0.9, 0.01}, {0.95, 0.005}, {0.99, 0.001}});
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> d(0, 100);
for (auto i = 1; i <= number_of_entries; ++i) summary.Observe(d(gen));
while (state.KeepRunning()) {
benchmark::DoNotOptimize(summary.Collect());
}
}
BENCHMARK(BM_Summary_Collect_Common)->Range(0, ITERATIONS);
@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "prometheus/detail/core_export.h"
#include "prometheus/metric_type.h"
namespace prometheus {
PROMETHEUS_CPP_CORE_EXPORT bool CheckMetricName(const std::string& name);
PROMETHEUS_CPP_CORE_EXPORT bool CheckLabelName(const std::string& name,
MetricType type);
} // namespace prometheus
@@ -0,0 +1,90 @@
#pragma once
#include <cstdint>
#include <string>
#include <tuple>
#include <vector>
#include "prometheus/detail/core_export.h"
namespace prometheus {
struct PROMETHEUS_CPP_CORE_EXPORT ClientMetric {
// Label
struct Label {
std::string name;
std::string value;
bool operator<(const Label& rhs) const {
return std::tie(name, value) < std::tie(rhs.name, rhs.value);
}
bool operator==(const Label& rhs) const {
return std::tie(name, value) == std::tie(rhs.name, rhs.value);
}
};
std::vector<Label> label;
// Counter
struct Counter {
double value = 0.0;
};
Counter counter;
// Gauge
struct Gauge {
double value = 0.0;
};
Gauge gauge;
// Info
struct Info {
double value = 1.0;
};
Info info;
// Summary
struct Quantile {
double quantile = 0.0;
double value = 0.0;
};
struct Summary {
std::uint64_t sample_count = 0;
double sample_sum = 0.0;
std::vector<Quantile> quantile;
};
Summary summary;
// Histogram
struct Bucket {
std::uint64_t cumulative_count = 0;
double upper_bound = 0.0;
};
struct Histogram {
std::uint64_t sample_count = 0;
double sample_sum = 0.0;
std::vector<Bucket> bucket;
};
Histogram histogram;
// Untyped
struct Untyped {
double value = 0;
};
Untyped untyped;
// Timestamp
std::int64_t timestamp_ms = 0;
};
} // namespace prometheus
@@ -0,0 +1,25 @@
#pragma once
#include <vector>
#include "prometheus/detail/core_export.h"
namespace prometheus {
struct MetricFamily;
}
namespace prometheus {
/// @brief Interface implemented by anything that can be used by Prometheus to
/// collect metrics.
///
/// A Collectable has to be registered for collection. See Registry.
class PROMETHEUS_CPP_CORE_EXPORT Collectable {
public:
virtual ~Collectable() = default;
/// \brief Returns a list of metrics and their samples.
virtual std::vector<MetricFamily> Collect() const = 0;
};
} // namespace prometheus
@@ -0,0 +1,82 @@
#pragma once
#include "prometheus/client_metric.h"
#include "prometheus/detail/builder.h" // IWYU pragma: export
#include "prometheus/detail/core_export.h"
#include "prometheus/gauge.h"
#include "prometheus/metric_type.h"
namespace prometheus {
/// \brief A counter metric to represent a monotonically increasing value.
///
/// This class represents the metric type counter:
/// https://prometheus.io/docs/concepts/metric_types/#counter
///
/// The value of the counter can only increase. Example of counters are:
/// - the number of requests served
/// - tasks completed
/// - errors
///
/// Do not use a counter to expose a value that can decrease - instead use a
/// Gauge.
///
/// The class is thread-safe. No concurrent call to any API of this type causes
/// a data race.
class PROMETHEUS_CPP_CORE_EXPORT Counter {
public:
static const MetricType metric_type{MetricType::Counter};
/// \brief Create a counter that starts at 0.
Counter() = default;
/// \brief Increment the counter by 1.
void Increment();
/// \brief Increment the counter by a given amount.
///
/// The counter will not change if the given amount is negative.
void Increment(double);
/// \brief Get the current value of the counter.
double Value() const;
/// \brief Get the current value of the counter.
///
/// Collect is called by the Registry when collecting metrics.
ClientMetric Collect() const;
private:
Gauge gauge_{0.0};
};
/// \brief Return a builder to configure and register a Counter metric.
///
/// @copydetails Family<>::Family()
///
/// Example usage:
///
/// \code
/// auto registry = std::make_shared<Registry>();
/// auto& counter_family = prometheus::BuildCounter()
/// .Name("some_name")
/// .Help("Additional description.")
/// .Labels({{"key", "value"}})
/// .Register(*registry);
///
/// ...
/// \endcode
///
/// \return An object of unspecified type T, i.e., an implementation detail
/// except that it has the following members:
///
/// - Name(const std::string&) to set the metric name,
/// - Help(const std::string&) to set an additional description.
/// - Labels(const Labels&) to assign a set of
/// key-value pairs (= labels) to the metric.
///
/// To finish the configuration of the Counter metric, register it with
/// Register(Registry&).
PROMETHEUS_CPP_CORE_EXPORT detail::Builder<Counter> BuildCounter();
} // namespace prometheus
@@ -0,0 +1,33 @@
#pragma once
#include <string>
#include "prometheus/labels.h"
// IWYU pragma: private
// IWYU pragma: no_include "prometheus/family.h"
namespace prometheus {
template <typename T>
class Family; // IWYU pragma: keep
class Registry; // IWYU pragma: keep
namespace detail {
template <typename T>
class Builder {
public:
Builder& Labels(const ::prometheus::Labels& labels);
Builder& Name(const std::string&);
Builder& Help(const std::string&);
Family<T>& Register(Registry&);
private:
::prometheus::Labels labels_;
std::string name_;
std::string help_;
};
} // namespace detail
} // namespace prometheus
@@ -0,0 +1,57 @@
#pragma once
#include <array>
#include <cstddef>
#include <functional>
#include <vector>
#include "prometheus/detail/core_export.h"
// IWYU pragma: private, include "prometheus/summary.h"
namespace prometheus {
namespace detail {
class PROMETHEUS_CPP_CORE_EXPORT CKMSQuantiles {
public:
struct PROMETHEUS_CPP_CORE_EXPORT Quantile {
Quantile(double quantile, double error);
double quantile;
double error;
double u;
double v;
};
private:
struct Item {
double value;
int g;
int delta;
Item(double value, int lower_delta, int delta);
};
public:
explicit CKMSQuantiles(const std::vector<Quantile>& quantiles);
void insert(double value);
double get(double q);
void reset();
private:
double allowableError(int rank);
bool insertBatch();
void compress();
private:
const std::reference_wrapper<const std::vector<Quantile>> quantiles_;
std::size_t count_;
std::vector<Item> sample_;
std::array<double, 500> buffer_;
std::size_t buffer_count_;
};
} // namespace detail
} // namespace prometheus
@@ -0,0 +1,37 @@
#pragma once
#include <chrono>
#include <cstddef>
#include <vector>
#include "prometheus/detail/ckms_quantiles.h" // IWYU pragma: export
#include "prometheus/detail/core_export.h"
// IWYU pragma: private, include "prometheus/summary.h"
namespace prometheus {
namespace detail {
class PROMETHEUS_CPP_CORE_EXPORT TimeWindowQuantiles {
using Clock = std::chrono::steady_clock;
public:
TimeWindowQuantiles(const std::vector<CKMSQuantiles::Quantile>& quantiles,
Clock::duration max_age_seconds, int age_buckets);
double get(double q) const;
void insert(double value);
private:
CKMSQuantiles& rotate() const;
const std::vector<CKMSQuantiles::Quantile>& quantiles_;
mutable std::vector<CKMSQuantiles> ckms_quantiles_;
mutable std::size_t current_bucket_;
mutable Clock::time_point last_rotation_;
const Clock::duration rotation_interval_;
};
} // namespace detail
} // namespace prometheus
@@ -0,0 +1,22 @@
#pragma once
#include <cstddef>
#include "prometheus/detail/core_export.h"
#include "prometheus/labels.h"
namespace prometheus {
namespace detail {
/// \brief Label hasher for use in STL containers.
struct PROMETHEUS_CPP_CORE_EXPORT LabelHasher {
/// \brief Compute the hash value of a map of labels.
///
/// \param labels The map that will be computed the hash value.
///
/// \returns The hash value of the given labels.
std::size_t operator()(const Labels& labels) const;
};
} // namespace detail
} // namespace prometheus
@@ -0,0 +1,156 @@
#pragma once
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
#include "prometheus/client_metric.h"
#include "prometheus/collectable.h"
#include "prometheus/detail/core_export.h"
#include "prometheus/detail/utils.h"
#include "prometheus/labels.h"
#include "prometheus/metric_family.h"
// IWYU pragma: no_include "prometheus/counter.h"
// IWYU pragma: no_include "prometheus/gauge.h"
// IWYU pragma: no_include "prometheus/histogram.h"
// IWYU pragma: no_include "prometheus/info.h"
// IWYU pragma: no_include "prometheus/summary.h"
namespace prometheus {
/// \brief A metric of type T with a set of labeled dimensions.
///
/// One of Prometheus main feature is a multi-dimensional data model with time
/// series data identified by metric name and key/value pairs, also known as
/// labels. A time series is a series of data points indexed (or listed or
/// graphed) in time order (https://en.wikipedia.org/wiki/Time_series).
///
/// An instance of this class is exposed as multiple time series during
/// scrape, i.e., one time series for each set of labels provided to Add().
///
/// For example it is possible to collect data for a metric
/// `http_requests_total`, with two time series:
///
/// - all HTTP requests that used the method POST
/// - all HTTP requests that used the method GET
///
/// The metric name specifies the general feature of a system that is
/// measured, e.g., `http_requests_total`. Labels enable Prometheus's
/// dimensional data model: any given combination of labels for the same
/// metric name identifies a particular dimensional instantiation of that
/// metric. For example a label for 'all HTTP requests that used the method
/// POST' can be assigned with `method= "POST"`.
///
/// Given a metric name and a set of labels, time series are frequently
/// identified using this notation:
///
/// <metric name> { < label name >= <label value>, ... }
///
/// It is required to follow the syntax of metric names and labels given by:
/// https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
///
/// The following metric and label conventions are not required for using
/// Prometheus, but can serve as both a style-guide and a collection of best
/// practices: https://prometheus.io/docs/practices/naming/
///
/// \tparam T One of the metric types Counter, Gauge, Histogram or Summary.
template <typename T>
class PROMETHEUS_CPP_CORE_EXPORT Family : public Collectable {
public:
/// \brief Create a new metric.
///
/// Every metric is uniquely identified by its name and a set of key-value
/// pairs, also known as labels. Prometheus's query language allows filtering
/// and aggregation based on metric name and these labels.
///
/// This example selects all time series that have the `http_requests_total`
/// metric name:
///
/// http_requests_total
///
/// It is possible to assign labels to the metric name. These labels are
/// propagated to each dimensional data added with Add(). For example if a
/// label `job= "prometheus"` is provided to this constructor, it is possible
/// to filter this time series with Prometheus's query language by appending
/// a set of labels to match in curly braces ({})
///
/// http_requests_total{job= "prometheus"}
///
/// For further information see: [Querying Basics]
/// (https://prometheus.io/docs/prometheus/latest/querying/basics/)
///
/// \param name Set the metric name.
/// \param help Set an additional description.
/// \param constant_labels Assign a set of key-value pairs (= labels) to the
/// metric. All these labels are propagated to each time series within the
/// metric.
/// \throw std::runtime_exception on invalid metric or label names.
Family(const std::string& name, const std::string& help,
const Labels& constant_labels);
/// \brief Add a new dimensional data.
///
/// Each new set of labels adds a new dimensional data and is exposed in
/// Prometheus as a time series. It is possible to filter the time series
/// with Prometheus's query language by appending a set of labels to match in
/// curly braces ({})
///
/// http_requests_total{job= "prometheus",method= "POST"}
///
/// \param labels Assign a set of key-value pairs (= labels) to the
/// dimensional data. The function does nothing, if the same set of labels
/// already exists.
/// \param args Arguments are passed to the constructor of metric type T. See
/// Counter, Gauge, Histogram or Summary for required constructor arguments.
/// \return Return the newly created dimensional data or - if a same set of
/// labels already exists - the already existing dimensional data.
/// \throw std::runtime_exception on invalid label names.
template <typename... Args>
T& Add(const Labels& labels, Args&&... args) {
return Add(labels, std::make_unique<T>(args...));
}
/// \brief Remove the given dimensional data.
///
/// \param metric Dimensional data to be removed. The function does nothing,
/// if the given metric was not returned by Add().
void Remove(T* metric);
/// \brief Returns true if the dimensional data with the given labels exist
///
/// \param labels A set of key-value pairs (= labels) of the dimensional data.
bool Has(const Labels& labels) const;
/// \brief Returns the name for this family.
///
/// \return The family name.
const std::string& GetName() const;
/// \brief Returns the constant labels for this family.
///
/// \return All constant labels as key-value pairs.
const Labels& GetConstantLabels() const;
/// \brief Returns the current value of each dimensional data.
///
/// Collect is called by the Registry when collecting metrics.
///
/// \return Zero or more samples for each dimensional data.
std::vector<MetricFamily> Collect() const override;
private:
std::unordered_map<Labels, std::unique_ptr<T>, detail::LabelHasher> metrics_;
const std::string name_;
const std::string help_;
const Labels constant_labels_;
mutable std::mutex mutex_;
ClientMetric CollectMetric(const Labels& labels, T* metric) const;
T& Add(const Labels& labels, std::unique_ptr<T> object);
};
} // namespace prometheus
@@ -0,0 +1,94 @@
#pragma once
#include <atomic>
#include "prometheus/client_metric.h"
#include "prometheus/detail/builder.h" // IWYU pragma: export
#include "prometheus/detail/core_export.h"
#include "prometheus/metric_type.h"
namespace prometheus {
/// \brief A gauge metric to represent a value that can arbitrarily go up and
/// down.
///
/// The class represents the metric type gauge:
/// https://prometheus.io/docs/concepts/metric_types/#gauge
///
/// Gauges are typically used for measured values like temperatures or current
/// memory usage, but also "counts" that can go up and down, like the number of
/// running processes.
///
/// The class is thread-safe. No concurrent call to any API of this type causes
/// a data race.
class PROMETHEUS_CPP_CORE_EXPORT Gauge {
public:
static const MetricType metric_type{MetricType::Gauge};
/// \brief Create a gauge that starts at 0.
Gauge() = default;
/// \brief Create a gauge that starts at the given amount.
explicit Gauge(double);
/// \brief Increment the gauge by 1.
void Increment();
/// \brief Increment the gauge by the given amount.
void Increment(double);
/// \brief Decrement the gauge by 1.
void Decrement();
/// \brief Decrement the gauge by the given amount.
void Decrement(double);
/// \brief Set the gauge to the given value.
void Set(double);
/// \brief Set the gauge to the current unix time in seconds.
void SetToCurrentTime();
/// \brief Get the current value of the gauge.
double Value() const;
/// \brief Get the current value of the gauge.
///
/// Collect is called by the Registry when collecting metrics.
ClientMetric Collect() const;
private:
void Change(double);
std::atomic<double> value_{0.0};
};
/// \brief Return a builder to configure and register a Gauge metric.
///
/// @copydetails Family<>::Family()
///
/// Example usage:
///
/// \code
/// auto registry = std::make_shared<Registry>();
/// auto& gauge_family = prometheus::BuildGauge()
/// .Name("some_name")
/// .Help("Additional description.")
/// .Labels({{"key", "value"}})
/// .Register(*registry);
///
/// ...
/// \endcode
///
/// \return An object of unspecified type T, i.e., an implementation detail
/// except that it has the following members:
///
/// - Name(const std::string&) to set the metric name,
/// - Help(const std::string&) to set an additional description.
/// - Labels(const Labels&) to assign a set of
/// key-value pairs (= labels) to the metric.
///
/// To finish the configuration of the Gauge metric register it with
/// Register(Registry&).
PROMETHEUS_CPP_CORE_EXPORT detail::Builder<Gauge> BuildGauge();
} // namespace prometheus
@@ -0,0 +1,109 @@
#pragma once
#include <mutex>
#include <vector>
#include "prometheus/client_metric.h"
#include "prometheus/counter.h"
#include "prometheus/detail/builder.h" // IWYU pragma: export
#include "prometheus/detail/core_export.h"
#include "prometheus/gauge.h"
#include "prometheus/metric_type.h"
namespace prometheus {
/// \brief A histogram metric to represent aggregatable distributions of events.
///
/// This class represents the metric type histogram:
/// https://prometheus.io/docs/concepts/metric_types/#histogram
///
/// A histogram tracks the number of observations and the sum of the observed
/// values, allowing to calculate the average of the observed values.
///
/// At its core a histogram has a counter per bucket. The sum of observations
/// also behaves like a counter as long as there are no negative observations.
///
/// See https://prometheus.io/docs/practices/histograms/ for detailed
/// explanations of histogram usage and differences to summaries.
///
/// The class is thread-safe. No concurrent call to any API of this type causes
/// a data race.
class PROMETHEUS_CPP_CORE_EXPORT Histogram {
public:
using BucketBoundaries = std::vector<double>;
static const MetricType metric_type{MetricType::Histogram};
/// \brief Create a histogram with manually chosen buckets.
///
/// The BucketBoundaries are a list of monotonically increasing values
/// representing the bucket boundaries. Each consecutive pair of values is
/// interpreted as a half-open interval [b_n, b_n+1) which defines one bucket.
///
/// There is no limitation on how the buckets are divided, i.e, equal size,
/// exponential etc..
///
/// The bucket boundaries cannot be changed once the histogram is created.
explicit Histogram(const BucketBoundaries& buckets);
/// \copydoc Histogram::Histogram(const BucketBoundaries&)
explicit Histogram(BucketBoundaries&& buckets);
/// \brief Observe the given amount.
///
/// The given amount selects the 'observed' bucket. The observed bucket is
/// chosen for which the given amount falls into the half-open interval [b_n,
/// b_n+1). The counter of the observed bucket is incremented. Also the total
/// sum of all observations is incremented.
void Observe(double value);
/// \brief Observe multiple data points.
///
/// Increments counters given a count for each bucket. (i.e. the caller of
/// this function must have already sorted the values into buckets).
/// Also increments the total sum of all observations by the given value.
void ObserveMultiple(const std::vector<double>& bucket_increments,
double sum_of_values);
/// \brief Get the current value of the histogram.
///
/// Collect is called by the Registry when collecting metrics.
ClientMetric Collect() const;
private:
BucketBoundaries bucket_boundaries_;
mutable std::mutex mutex_;
std::vector<Counter> bucket_counts_;
Gauge sum_;
};
/// \brief Return a builder to configure and register a Histogram metric.
///
/// @copydetails Family<>::Family()
///
/// Example usage:
///
/// \code
/// auto registry = std::make_shared<Registry>();
/// auto& histogram_family = prometheus::BuildHistogram()
/// .Name("some_name")
/// .Help("Additional description.")
/// .Labels({{"key", "value"}})
/// .Register(*registry);
///
/// ...
/// \endcode
///
/// \return An object of unspecified type T, i.e., an implementation detail
/// except that it has the following members:
///
/// - Name(const std::string&) to set the metric name,
/// - Help(const std::string&) to set an additional description.
/// - Labels(const Labels&) to assign a set of
/// key-value pairs (= labels) to the metric.
///
/// To finish the configuration of the Histogram metric register it with
/// Register(Registry&).
PROMETHEUS_CPP_CORE_EXPORT detail::Builder<Histogram> BuildHistogram();
} // namespace prometheus
@@ -0,0 +1,68 @@
#pragma once
#include "prometheus/client_metric.h"
#include "prometheus/detail/builder.h" // IWYU pragma: export
#include "prometheus/detail/core_export.h"
#include "prometheus/metric_type.h"
namespace prometheus {
/// \brief A info metric to represent textual information which should not
/// change during process lifetime.
///
/// This class represents the metric type info:
/// https://github.com/OpenObservability/OpenMetrics/blob/98ae26c87b1c3bcf937909a880b32c8be643cc9b/specification/OpenMetrics.md#info
/// Prometheus does not provide this type directly, it is used by emulating a
/// gauge with value 1: https://prometheus.io/docs/concepts/metric_types/#gauge
///
/// The value of the info cannot change. Example of infos are:
/// - the application's version
/// - revision control commit
/// - version of the compiler
///
/// The class is thread-safe. No concurrent call to any API of this type causes
/// a data race.
class PROMETHEUS_CPP_CORE_EXPORT Info {
public:
static const MetricType metric_type{MetricType::Info};
/// \brief Create a info.
Info() = default;
/// \brief Get the current value of the info.
///
/// Collect is called by the Registry when collecting metrics.
ClientMetric Collect() const;
};
/// \brief Return a builder to configure and register a Info metric.
///
/// @copydetails Family<>::Family()
///
/// Example usage:
///
/// \code
/// auto registry = std::make_shared<Registry>();
/// auto& info_family = prometheus::BuildInfo()
/// .Name("some_name")
/// .Help("Additional description.")
/// .Labels({{"key", "value"}})
/// .Register(*registry);
///
/// ...
/// \endcode
///
/// \return An object of unspecified type T, i.e., an implementation detail
/// except that it has the following members:
///
/// - Name(const std::string&) to set the metric name,
/// - Help(const std::string&) to set an additional description.
/// - Labels(const Labels&) to assign a set of
/// key-value pairs (= labels) to the metric.
///
/// To finish the configuration of the Info metric, register it with
/// Register(Registry&).
PROMETHEUS_CPP_CORE_EXPORT detail::Builder<Info> BuildInfo();
} // namespace prometheus
@@ -0,0 +1,11 @@
#pragma once
#include <map>
#include <string>
namespace prometheus {
/// \brief Multiple labels and their value.
using Labels = std::map<std::string, std::string>;
} // namespace prometheus
@@ -0,0 +1,18 @@
#pragma once
#include <string>
#include <vector>
#include "prometheus/client_metric.h"
#include "prometheus/detail/core_export.h"
#include "prometheus/metric_type.h"
namespace prometheus {
struct PROMETHEUS_CPP_CORE_EXPORT MetricFamily {
std::string name;
std::string help;
MetricType type = MetricType::Untyped;
std::vector<ClientMetric> metric;
};
} // namespace prometheus
@@ -0,0 +1,14 @@
#pragma once
namespace prometheus {
enum class MetricType {
Counter,
Gauge,
Summary,
Untyped,
Histogram,
Info,
};
} // namespace prometheus
@@ -0,0 +1,120 @@
#pragma once
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include "prometheus/collectable.h"
#include "prometheus/detail/core_export.h"
#include "prometheus/family.h"
#include "prometheus/labels.h"
#include "prometheus/metric_family.h"
namespace prometheus {
class Counter;
class Gauge;
class Histogram;
class Info;
class Summary;
namespace detail {
template <typename T>
class Builder; // IWYU pragma: keep
}
/// \brief Manages the collection of a number of metrics.
///
/// The Registry is responsible to expose data to a class/method/function
/// "bridge", which returns the metrics in a format Prometheus supports.
///
/// The key class is the Collectable. This has a method - called Collect() -
/// that returns zero or more metrics and their samples. The metrics are
/// represented by the class Family<>, which implements the Collectable
/// interface. A new metric is registered with BuildCounter(), BuildGauge(),
/// BuildHistogram(), BuildInfo() or BuildSummary().
///
/// The class is thread-safe. No concurrent call to any API of this type causes
/// a data race.
class PROMETHEUS_CPP_CORE_EXPORT Registry : public Collectable {
public:
/// \brief How to deal with repeatedly added family names for a type.
///
/// Adding a family with the same name but different types is always an error
/// and will lead to an exception.
enum class InsertBehavior {
/// \brief If a family with the same name and labels already exists return
/// the existing one. If no family with that name exists create it.
/// Otherwise throw.
Merge,
/// \brief Throws if a family with the same name already exists.
Throw,
};
/// \brief name Create a new registry.
///
/// \param insert_behavior How to handle families with the same name.
explicit Registry(InsertBehavior insert_behavior = InsertBehavior::Merge);
/// \brief Deleted copy constructor.
Registry(const Registry&) = delete;
/// \brief Deleted copy assignment.
Registry& operator=(const Registry&) = delete;
/// \brief Deleted move constructor.
Registry(Registry&&) = delete;
/// \brief Deleted move assignment.
Registry& operator=(Registry&&) = delete;
/// \brief name Destroys a registry.
~Registry() override;
/// \brief Returns a list of metrics and their samples.
///
/// Every time the Registry is scraped it calls each of the metrics Collect
/// function.
///
/// \return Zero or more metrics and their samples.
std::vector<MetricFamily> Collect() const override;
/// \brief Removes a metrics family from the registry.
///
/// Please note that this operation invalidates the previously
/// returned reference to the Family and all of their added
/// metric objects.
///
/// \tparam T One of the metric types Counter, Gauge, Histogram or Summary.
/// \param family The family to remove
///
/// \return True if the family was found and removed.
template <typename T>
bool Remove(const Family<T>& family);
private:
template <typename T>
friend class detail::Builder;
template <typename T>
std::vector<std::unique_ptr<Family<T>>>& GetFamilies();
template <typename T>
bool NameExistsInOtherType(const std::string& name) const;
template <typename T>
Family<T>& Add(const std::string& name, const std::string& help,
const Labels& labels);
const InsertBehavior insert_behavior_;
std::vector<std::unique_ptr<Family<Counter>>> counters_;
std::vector<std::unique_ptr<Family<Gauge>>> gauges_;
std::vector<std::unique_ptr<Family<Histogram>>> histograms_;
std::vector<std::unique_ptr<Family<Info>>> infos_;
std::vector<std::unique_ptr<Family<Summary>>> summaries_;
mutable std::mutex mutex_;
};
} // namespace prometheus
@@ -0,0 +1,20 @@
#pragma once
#include <iosfwd>
#include <string>
#include <vector>
#include "prometheus/detail/core_export.h"
#include "prometheus/metric_family.h"
namespace prometheus {
class PROMETHEUS_CPP_CORE_EXPORT Serializer {
public:
virtual ~Serializer() = default;
virtual std::string Serialize(const std::vector<MetricFamily>&) const;
virtual void Serialize(std::ostream& out,
const std::vector<MetricFamily>& metrics) const = 0;
};
} // namespace prometheus
@@ -0,0 +1,128 @@
#pragma once
#include <chrono>
#include <cstdint>
#include <mutex>
#include <vector>
#include "prometheus/client_metric.h"
#include "prometheus/detail/builder.h" // IWYU pragma: export
#include "prometheus/detail/ckms_quantiles.h"
#include "prometheus/detail/core_export.h"
#include "prometheus/detail/time_window_quantiles.h"
#include "prometheus/metric_type.h"
namespace prometheus {
/// \brief A summary metric samples observations over a sliding window of time.
///
/// This class represents the metric type summary:
/// https://prometheus.io/docs/instrumenting/writing_clientlibs/#summary
///
/// A summary provides a total count of observations and a sum of all observed
/// values. In contrast to a histogram metric it also calculates configurable
/// Phi-quantiles over a sliding window of time.
///
/// The essential difference between summaries and histograms is that summaries
/// calculate streaming Phi-quantiles on the client side and expose them
/// directly, while histograms expose bucketed observation counts and the
/// calculation of quantiles from the buckets of a histogram happens on the
/// server side:
/// https://prometheus.io/docs/prometheus/latest/querying/functions/#histogram_quantile.
///
/// Note that Phi designates the probability density function of the standard
/// Gaussian distribution.
///
/// See https://prometheus.io/docs/practices/histograms/ for detailed
/// explanations of Phi-quantiles, summary usage, and differences to histograms.
///
/// The class is thread-safe. No concurrent call to any API of this type causes
/// a data race.
class PROMETHEUS_CPP_CORE_EXPORT Summary {
public:
using Quantiles = std::vector<detail::CKMSQuantiles::Quantile>;
static const MetricType metric_type{MetricType::Summary};
/// \brief Create a summary metric.
///
/// \param quantiles A list of 'targeted' Phi-quantiles. A targeted
/// Phi-quantile is specified in the form of a Phi-quantile and tolerated
/// error. For example a Quantile{0.5, 0.1} means that the median (= 50th
/// percentile) should be returned with 10 percent error or a Quantile{0.2,
/// 0.05} means the 20th percentile with 5 percent tolerated error. Note that
/// percentiles and quantiles are the same concept, except percentiles are
/// expressed as percentages. The Phi-quantile must be in the interval [0, 1].
/// Note that a lower tolerated error for a Phi-quantile results in higher
/// usage of resources (memory and cpu) to calculate the summary.
///
/// The Phi-quantiles are calculated over a sliding window of time. The
/// sliding window of time is configured by max_age and age_buckets.
///
/// \param max_age Set the duration of the time window, i.e., how long
/// observations are kept before they are discarded. The default value is 60
/// seconds.
///
/// \param age_buckets Set the number of buckets of the time window. It
/// determines the number of buckets used to exclude observations that are
/// older than max_age from the summary, e.g., if max_age is 60 seconds and
/// age_buckets is 5, buckets will be switched every 12 seconds. The value is
/// a trade-off between resources (memory and cpu for maintaining the bucket)
/// and how smooth the time window is moved. With only one age bucket it
/// effectively results in a complete reset of the summary each time max_age
/// has passed. The default value is 5.
explicit Summary(const Quantiles& quantiles,
std::chrono::milliseconds max_age = std::chrono::seconds{60},
int age_buckets = 5);
/// \copydoc Summary::Summary(const Quantiles&,std::chrono::milliseconds,int)
explicit Summary(Quantiles&& quantiles,
std::chrono::milliseconds max_age = std::chrono::seconds{60},
int age_buckets = 5);
/// \brief Observe the given amount.
void Observe(double value);
/// \brief Get the current value of the summary.
///
/// Collect is called by the Registry when collecting metrics.
ClientMetric Collect() const;
private:
Quantiles quantiles_;
mutable std::mutex mutex_;
std::uint64_t count_{};
double sum_{};
detail::TimeWindowQuantiles quantile_values_;
};
/// \brief Return a builder to configure and register a Summary metric.
///
/// @copydetails Family<>::Family()
///
/// Example usage:
///
/// \code
/// auto registry = std::make_shared<Registry>();
/// auto& summary_family = prometheus::BuildSummary()
/// .Name("some_name")
/// .Help("Additional description.")
/// .Labels({{"key", "value"}})
/// .Register(*registry);
///
/// ...
/// \endcode
///
/// \return An object of unspecified type T, i.e., an implementation detail
/// except that it has the following members:
///
/// - Name(const std::string&) to set the metric name,
/// - Help(const std::string&) to set an additional description.
/// - Labels(const Labels&) to assign a set of
/// key-value pairs (= labels) to the metric.
///
/// To finish the configuration of the Summary metric register it with
/// Register(Registry&).
PROMETHEUS_CPP_CORE_EXPORT detail::Builder<Summary> BuildSummary();
} // namespace prometheus
@@ -0,0 +1,19 @@
#pragma once
#include <iosfwd>
#include <vector>
#include "prometheus/detail/core_export.h"
#include "prometheus/metric_family.h"
#include "prometheus/serializer.h"
namespace prometheus {
class PROMETHEUS_CPP_CORE_EXPORT TextSerializer : public Serializer {
public:
using Serializer::Serialize;
void Serialize(std::ostream& out,
const std::vector<MetricFamily>& metrics) const override;
};
} // namespace prometheus
@@ -0,0 +1,85 @@
#include "prometheus/check_names.h"
#include <algorithm>
#include <iterator>
namespace prometheus {
namespace {
bool isLocaleIndependentAlphaNumeric(char c) {
return ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
('A' <= c && c <= 'Z');
}
bool isLocaleIndependentDigit(char c) { return '0' <= c && c <= '9'; }
bool nameStartsValid(const std::string& name) {
// must not be empty
if (name.empty()) {
return false;
}
// must not start with a digit
if (isLocaleIndependentDigit(name.front())) {
return false;
}
// must not start with "__"
auto reserved_for_internal_purposes = name.compare(0, 2, "__") == 0;
if (reserved_for_internal_purposes) return false;
return true;
}
} // anonymous namespace
/// \brief Check if the metric name is valid
///
/// The metric name regex is "[a-zA-Z_:][a-zA-Z0-9_:]*"
///
/// \see https://prometheus.io/docs/concepts/data_model/
///
/// \param name metric name
/// \return true is valid, false otherwise
bool CheckMetricName(const std::string& name) {
if (!nameStartsValid(name)) {
return false;
}
auto validMetricCharacters = [](char c) {
return isLocaleIndependentAlphaNumeric(c) || c == '_' || c == ':';
};
auto mismatch =
std::find_if_not(std::begin(name), std::end(name), validMetricCharacters);
return mismatch == std::end(name);
}
/// \brief Check if the label name is valid
///
/// The label name regex is "[a-zA-Z_][a-zA-Z0-9_]*"
///
/// \see https://prometheus.io/docs/concepts/data_model/
///
/// \param name label name
/// \param type metric type
/// \return true is valid, false otherwise
bool CheckLabelName(const std::string& name, MetricType type) {
if (!nameStartsValid(name)) {
return false;
}
auto validLabelCharacters = [](char c) {
return isLocaleIndependentAlphaNumeric(c) || c == '_';
};
if ((type == MetricType::Histogram && name == "le") ||
(type == MetricType::Summary && name == "quantile")) {
return false;
}
auto mismatch =
std::find_if_not(std::begin(name), std::end(name), validLabelCharacters);
return mismatch == std::end(name);
}
} // namespace prometheus
@@ -0,0 +1,22 @@
#include "prometheus/counter.h"
namespace prometheus {
void Counter::Increment() { gauge_.Increment(); }
void Counter::Increment(const double val) {
if (val < 0.0) {
return;
}
gauge_.Increment(val);
}
double Counter::Value() const { return gauge_.Value(); }
ClientMetric Counter::Collect() const {
ClientMetric metric;
metric.counter.value = Value();
return metric;
}
} // namespace prometheus
@@ -0,0 +1,52 @@
#include "prometheus/detail/builder.h"
#include "prometheus/counter.h"
#include "prometheus/detail/core_export.h"
#include "prometheus/gauge.h"
#include "prometheus/histogram.h"
#include "prometheus/info.h"
#include "prometheus/registry.h"
#include "prometheus/summary.h"
namespace prometheus {
namespace detail {
template <typename T>
Builder<T>& Builder<T>::Labels(const ::prometheus::Labels& labels) {
labels_ = labels;
return *this;
}
template <typename T>
Builder<T>& Builder<T>::Name(const std::string& name) {
name_ = name;
return *this;
}
template <typename T>
Builder<T>& Builder<T>::Help(const std::string& help) {
help_ = help;
return *this;
}
template <typename T>
Family<T>& Builder<T>::Register(Registry& registry) {
return registry.Add<T>(name_, help_, labels_);
}
template class PROMETHEUS_CPP_CORE_EXPORT Builder<Counter>;
template class PROMETHEUS_CPP_CORE_EXPORT Builder<Gauge>;
template class PROMETHEUS_CPP_CORE_EXPORT Builder<Histogram>;
template class PROMETHEUS_CPP_CORE_EXPORT Builder<Info>;
template class PROMETHEUS_CPP_CORE_EXPORT Builder<Summary>;
} // namespace detail
detail::Builder<Counter> BuildCounter() { return {}; }
detail::Builder<Gauge> BuildGauge() { return {}; }
detail::Builder<Histogram> BuildHistogram() { return {}; }
detail::Builder<Info> BuildInfo() { return {}; }
detail::Builder<Summary> BuildSummary() { return {}; }
} // namespace prometheus
@@ -0,0 +1,153 @@
#include "prometheus/detail/ckms_quantiles.h" // IWYU pragma: export
#include <algorithm>
#include <cmath>
#include <limits>
#include <memory>
namespace prometheus {
namespace detail {
CKMSQuantiles::Quantile::Quantile(double quantile, double error)
: quantile(quantile),
error(error),
u(2.0 * error / (1.0 - quantile)),
v(2.0 * error / quantile) {}
CKMSQuantiles::Item::Item(double value, int lower_delta, int delta)
: value(value), g(lower_delta), delta(delta) {}
CKMSQuantiles::CKMSQuantiles(const std::vector<Quantile>& quantiles)
: quantiles_(quantiles), count_(0), buffer_{}, buffer_count_(0) {}
void CKMSQuantiles::insert(double value) {
buffer_[buffer_count_] = value;
++buffer_count_;
if (buffer_count_ == buffer_.size()) {
insertBatch();
compress();
}
}
double CKMSQuantiles::get(double q) {
insertBatch();
compress();
if (sample_.empty()) {
return std::numeric_limits<double>::quiet_NaN();
}
int rankMin = 0;
const auto desired = static_cast<int>(q * count_);
const auto bound = desired + (allowableError(desired) / 2);
auto it = sample_.begin();
decltype(it) prev;
auto cur = it++;
while (it != sample_.end()) {
prev = cur;
cur = it++;
rankMin += prev->g;
if (rankMin + cur->g + cur->delta > bound) {
return prev->value;
}
}
return sample_.back().value;
}
void CKMSQuantiles::reset() {
count_ = 0;
sample_.clear();
buffer_count_ = 0;
}
double CKMSQuantiles::allowableError(int rank) {
auto size = sample_.size();
double minError = size + 1;
for (const auto& q : quantiles_.get()) {
double error;
if (rank <= q.quantile * size) {
error = q.u * (size - rank);
} else {
error = q.v * rank;
}
if (error < minError) {
minError = error;
}
}
return minError;
}
bool CKMSQuantiles::insertBatch() {
if (buffer_count_ == 0) {
return false;
}
std::sort(buffer_.begin(), buffer_.begin() + buffer_count_);
std::size_t start = 0;
if (sample_.empty()) {
sample_.emplace_back(buffer_[0], 1, 0);
++start;
++count_;
}
std::size_t idx = 0;
std::size_t item = idx++;
for (std::size_t i = start; i < buffer_count_; ++i) {
double v = buffer_[i];
while (idx < sample_.size() && sample_[item].value < v) {
item = idx++;
}
if (sample_[item].value > v) {
--idx;
}
int delta;
if (idx - 1 == 0 || idx + 1 == sample_.size()) {
delta = 0;
} else {
delta = static_cast<int>(std::floor(allowableError(idx + 1))) + 1;
}
sample_.emplace(sample_.begin() + idx, v, 1, delta);
count_++;
item = idx++;
}
buffer_count_ = 0;
return true;
}
void CKMSQuantiles::compress() {
if (sample_.size() < 2) {
return;
}
std::size_t idx = 0;
std::size_t prev;
std::size_t next = idx++;
while (idx < sample_.size()) {
prev = next;
next = idx++;
if (sample_[prev].g + sample_[next].g + sample_[next].delta <=
allowableError(idx - 1)) {
sample_[next].g += sample_[prev].g;
sample_.erase(sample_.begin() + prev);
}
}
}
} // namespace detail
} // namespace prometheus
@@ -0,0 +1,39 @@
#pragma once
#include <cstddef>
#include <functional>
namespace prometheus {
namespace detail {
/// \brief Combine a hash value with nothing.
/// It's the boundary condition of this serial functions.
///
/// \param seed Not effect.
inline void hash_combine(std::size_t*) {}
/// \brief Combine the given hash value with another object.
///
/// \param seed The given hash value. It's a input/output parameter.
/// \param value The object that will be combined with the given hash value.
template <typename T>
inline void hash_combine(std::size_t* seed, const T& value) {
*seed ^= std::hash<T>{}(value) + 0x9e3779b9 + (*seed << 6) + (*seed >> 2);
}
/// \brief Combine the given hash value with another objects. It's a recursion。
///
/// \param seed The give hash value. It's a input/output parameter.
/// \param value The object that will be combined with the given hash value.
/// \param args The objects that will be combined with the given hash value.
template <typename T, typename... Types>
inline void hash_combine(std::size_t* seed, const T& value,
const Types&... args) {
hash_combine(seed, value);
hash_combine(seed, args...);
}
} // namespace detail
} // namespace prometheus

Some files were not shown because too many files have changed in this diff Show More