Skip to content

Commit

Permalink
Instrumenting Polycube with Prometheus Metrics (#313)
Browse files Browse the repository at this point in the history
* jsoncons and prometheus-cpp library, parser modification, modification of some services by adding metrics in yang files, creation of metrics in the server, exposing metrics to an endpoint
* add documentation for developer, for user and a README with links to library used (jsoncons and prometheus-cpp)
* deletion of some useless files in jsoncons, add code in install.sh to support Prometheus-cpp
* test for prometheus metrics
  • Loading branch information
pinoOgni committed Aug 3, 2020
1 parent ced3496 commit 245ed49
Show file tree
Hide file tree
Showing 117 changed files with 36,661 additions and 49 deletions.
58 changes: 58 additions & 0 deletions Documentation/advanced-features/open-metrics-support.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
View metrics
=================================

Raw metrics
-----------

To see the raw metrics just run polycube and go to http://localhost:9000/polycube/v1/metrics,
every time this page is refreshed, the metrics are updated, reading the cubes in run. Something like this::

#HELP ddos_stats_pkts_packets Total Dropped Packets
#TYPE ddos_stats_pkts_packets counter
ddos_stats_pkts_packets{cubeName="d1"} 4.000000
ddos_stats_pkts_packets{cubeName="d2"} 0.000000
#HELP ddos_blacklist_src_addresses Number of addresses in blacklist-src
#TYPE ddos_blacklist_src_addresses gauge
ddos_blacklist_src_addresses{cubeName="d1"} 3.000000
ddos_blacklist_src_addresses{cubeName="d2"} 0.000000
#HELP ddos_blacklist_dst_addresses Number of addresses in blacklist-dst
#TYPE ddos_blacklist_dst_addresses gauge
ddos_blacklist_dst_addresses{cubeName="d1"} 0.000000
ddos_blacklist_dst_addresses{cubeName="d2"} 0.000000





Something more interesting
--------------------------



To make graphs based on metrics and/or also to query metrics extracted from cubes



1. download Prometheus (follow the information on the `official page <https://prometheus.io/docs/introduction/first_steps/>`_) and edit the file "prometheus.yml"
1. modify the part of static_configs, removing the targets and adding this:
::

- targets: ['localhost: 9000']
metrics_path: '/polycube/v1/metrics'

2. to launch Prometheus just go to the Prometheus folder and
::
./prometheus --config.file = prometheus.yml

3. Now you can go to http://localhost:9090/graph


It is also possible to use Grafana, just follow the `official documentation <https://grafana.com/docs/grafana/latest/getting-started/getting-started/>`_ and set Prometheus as a datasource.



This is an example screenshot:

.. image:: ../images/metrics_example_grafana.png
81 changes: 81 additions & 0 deletions Documentation/developers/polycube-metrics.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
Polyube metrics
=================================

**In brief**

We have defined a way to be able to add metrics to each service dynamically, without heavily modifying the parser.

Done
----------
- [X] The core of prometheus-cpp library has been added
- [X] Extensions added in polycube-base.yang to support metrics in OpenMetrics format
- [X] Data structures have been added in ServiceMetadata in management_interface.h file
- [X] Metrics (Counter, Gauge) added in the yang of some services
- [X] Prototypes in Yang.h then in YangNodes.tcpp have been changed (ServiceMetadata* md parameter has been added) to allow the saving of the metrics read by the yang that will eventually be used on the rest server
- [X] Adding code in some parser methods to read metric extensions and to save
- [X] In the rest server (header) the data structures that are used to support, collect and record metrics have been defined.
- [X] A function has been created in the rest server that fills the data structures once to record the metrics read by the service yangs
- [X] Thanks to get_metrics all read metrics are exported to an endpoint /metrics,
- [X] The jsoncons library has been added (thanks to jsonpath written in the extensions of a yang file you can access the metric value through the json of a service)
- [X] Access the entire json of a service and use jsonpath to read the value of a metric
- [X] Definition of metrics per cube thanks to the use of labels (example: cubeName=d1)
- [] Add metrics to other services
- [X] Add tests



Prometheus-cpp
---------------
The library chosen to create metrics was `Prometheus-cpp <https://github.com/jupp0r/prometheus-cpp.git>`_ . In brief, from the official documentation: this library aims to enable Metrics-Driven Development for C++ services. It implements the Prometheus 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.
The whole library was not used, in fact only the core part is necessary for the creation and maintenance of the metrics since the exposure of the metrics is done using the rest server with Pistache.


Extensions added for metrics in OpenMetrics format:

- polycube-base:name-metric
- polycube-base:type-metric
- polycube-base:help-metric


In addition:

- polycube-base:path-metric: this extension has been added to get the value of a metric from an instantiated service
- polycube-base:type-operation: this extension has been added to overcome the problem that jsonpath does not allow (in a single query) to apply the "length" operator after a filter and in some cases we need it. Maybe it's not the best solution so maybe in the future it will be improved in some other way.


Jsoncons
--------
The library chosen to obtain the value of a metric from the json of an instanced cube used the jsonpath is `jsoncons <https://github.com/danielaparker/jsoncons>`_.
In brief, from the official documentation: jsoncons is a C++, header-only library for constructing JSON and JSON-like data formats such as CBOR.

In particular we use the extension of jsonpath that implements Stefan Goessner's JSONPath. It also supports search and replace using JSONPath expressions.



How to add metrics to a service
--------------------------------
To add a metric to a service you must add the extensions defined in polycube-base.yang to the chosen point of the service yang file (which can be a leaf, a container or a list):

- polycube-base:name-metric: you must respect OpenMetrics rules

- polycube-base:type-metric: GAUGE, COUNTER

- polycube-base:help-metric: a summary to help those who read the metrics

- polycube-base:path-metric: from the polycube-codegen output file (with a few modifications) you have to take the jsonpath up to the point where the metric is written. Another way is to use polycubectl to create a cube with the desired characteristics, print the json of the cube and derive the jsonpath. It is possible to use this tool https://jsonpath.com/ online

- polycube-base:typo-operation: in some cases you jsonpath is not enough to get the correct value for a metric (does not allow to apply "length" on a filtered json)





Future
--------------------------------

As is natural, there are improvements to be made and also new proposals presented on the current implementation:

- remove the type-operation annotation
- add a file (maybe even a yang) linked to the yang of a service, where you can write a list of possible metrics using the extensions already defined. This would bring enormous advantages since with the current implementation it is possible to define only one metric for each element of the yang that is a leaf or list or similar.
- introduce the ability to add metrics directly using polycubectl

Binary file added Documentation/images/metrics_example_grafana.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,20 @@ set -e

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

echo "Install Prometheus-cpp"
cd src/libs/prometheus-cpp
set +e
if [ -d _build ]; then
$SUDO rm -rf _build
fi
mkdir _build
cd _build
cmake .. -DBUILD_SHARED_LIBS=ON
make -j $(getconf _NPROCESSORS_ONLN)
$SUDO make install

cd $DIR/..

source scripts/pre-requirements.sh

echo "Install polycube"
Expand Down
2 changes: 1 addition & 1 deletion scripts/pre-requirements.sh
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,4 @@ $SUDO ldconfig
if [[ -z "${GOPATH}" ]]; then
mkdir -p $HOME/go
export GOPATH=$HOME/go
fi
fi
4 changes: 3 additions & 1 deletion src/libs/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
add_subdirectory(bcc EXCLUDE_FROM_ALL)
add_subdirectory(polycube)
add_subdirectory(viface)
add_subdirectory(spdlog)
add_subdirectory(spdlog)
add_subdirectory(jsoncons)
add_subdirectory(prometheus-cpp)
61 changes: 61 additions & 0 deletions src/libs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
Libraries used by Polycube
--------------------------

This folder includes all the libraries that are required by Polycube and that are statically included in the source files.

Although this makes more difficult the update of the above libraries to more recent versions, these are used for limited purposes and hence this necessity should not be so common. In exchange, this guarantees that the Polycube code always compiles with the above components.

BCC
----

From the official Githubn of `BCC <https://github.com/iovisor/bcc>`: BPF Compiler Collection or BCC is a toolkit for creating efficient kernel tracing and manipulation programs, and includes several useful tools and examples. It makes use of extended BPF (Berkeley Packet Filters), formally known as eBPF, a new feature that was first added to Linux 3.15. Much of what BCC uses requires Linux 4.1 and above.

Jsoncons
--------

The library chosen to obtain the value of a metric from the json of an instanced cube used the jsonpath is `jsoncons <https://github.com/danielaparker/jsoncons>`_.
In brief, from the official documentation: jsoncons is a C++, header-only library for constructing JSON and JSON-like data formats such as CBOR.

In particular we use the extension of jsonpath that implements Stefan Goessner's JSONPath. It also supports search and replace using JSONPath expressions.

All extensions except jsonpath have been deleted and documentation files, examples, tests and more that have not been used have been deleted. All this to reduce the amount of code and keep only what is actually used.

In addition, the CMakeList file has been modified to adapt to the changes made, for example the test part has been removed.

If you want to know how this library is used in Polycube, check the developer metrics in the documentation.

To compile this library you need only to run the main makefile.


polycube
---------

This library contains some common code that can be reused across multiple network functions. In facilitates the creation of links between services (i.e., to create a service chain), it provides common primitives such as a logging system, it facilitates the access to eBPF maps, and more. This library leverages [BCC](https://github.com/iovisor/bcc/) for compiling and injecting eBPF programs into the kernel.


Prometheus-cpp
---------------
The library chosen to create metrics was `Prometheus-cpp <https://github.com/jupp0r/prometheus-cpp.git>`_ .

Also for Prometheus-cpp we have tried to minimize the code and keep only what is used, deleting the documentation and other files that are not used. In particular, only the core part needed to create and manage metrics remains. The pull and push parts that have not been used have been canceled, as googletest and civitweb as submodules (3rdparty) have also been eliminated.

In addition, the CMakeList file has been modified to adapt to the changes made, for example the parts that dealt with the tests, the submodules and the push and pull parts have been deleted.

If you want to know how this library is used in Polycube, check the developer metrics in the documentation.

spdlog
------
From the official Github of `spdlog<https://github.com/gabime/spdlog>`: very fast, header-only/compiled, C++ logging library.

viface
------

From the official Github of `libviface<https://github.com/HPENetworking/libviface>`: libviface is a small C++11 library that allows to create (or hook to) and configure network interfaces in Linux based Operating Systems.

About the integration in Polycube
---------------------------------
For the bcc library is created a .so file to have the link of the shared library.

For the prometheus-cpp library we use in the install.sh file the "-DBUILD_SHARED_LIBS=ON" flag so we have the link of the shared library but if you set "-DBUILD_SHARED_LIBS=OFF" you can have a static library (.a file).

Libraries like jsoncons, polcyube, spdlog and viface are included directly.
66 changes: 66 additions & 0 deletions src/libs/jsoncons/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
cmake_minimum_required(VERSION 3.0.2)

project(jsoncons)

set(JSONCONS_PROJECT_DIR ${PROJECT_SOURCE_DIR})
set(JSONCONS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)

# Versioning
# ==========

file(STRINGS "${JSONCONS_INCLUDE_DIR}/jsoncons/config/version.hpp" jsoncons_version_defines
REGEX "#define JSONCONS_VERSION_(MAJOR|MINOR|PATCH)")
foreach(ver ${jsoncons_version_defines})
if(ver MATCHES "#define JSONCONS_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$")
set(JSONCONS_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "")
endif()
endforeach()
set(${PROJECT_NAME}_VERSION
${JSONCONS_VERSION_MAJOR}.${JSONCONS_VERSION_MINOR}.${JSONCONS_VERSION_PATCH})
message(STATUS "jsoncons v${${PROJECT_NAME}_VERSION}")

# Build
# =====

file(GLOB_RECURSE JSONCONS_HEADERS ${JSONCONS_INCLUDE_DIR}/*.hpp)

add_library(jsoncons INTERFACE)
target_include_directories(jsoncons INTERFACE $<BUILD_INTERFACE:${JSONCONS_INCLUDE_DIR}>
$<INSTALL_INTERFACE:include>)

# Installation
# ============

include(GNUInstallDirs)
include(CMakePackageConfigHelpers)

install(TARGETS jsoncons
EXPORT ${PROJECT_NAME}-targets)

# Makes the project importable from the build directory
export(EXPORT ${PROJECT_NAME}-targets
FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake")

install(DIRECTORY ${JSONCONS_INCLUDE_DIR}/jsoncons
${JSONCONS_INCLUDE_DIR}/jsoncons_ext
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

# GNUInstallDirs "DATADIR" wrong here; CMake search path wants "share".
set(JSONCONS_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE STRING "install path for jsonconsConfig.cmake")

configure_package_config_file(build_files/cmake/config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION ${JSONCONS_CMAKECONFIG_INSTALL_DIR})

# jsoncons is header-only and does not depend on the architecture.

write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
VERSION ${${PROJECT_NAME}_VERSION}
COMPATIBILITY AnyNewerVersion)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
DESTINATION ${JSONCONS_CMAKECONFIG_INSTALL_DIR})
install(EXPORT ${PROJECT_NAME}-targets
FILE ${PROJECT_NAME}Targets.cmake
DESTINATION ${JSONCONS_CMAKECONFIG_INSTALL_DIR})

28 changes: 28 additions & 0 deletions src/libs/jsoncons/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright Daniel Parker 2013 - 2017.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE or copy at
// http://www.boost.org/LICENSE_1_0.txt)

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

0 comments on commit 245ed49

Please sign in to comment.