Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
4dc849fa
Commit
4dc849fa
authored
Jun 17, 2020
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Streamline metric registry API and metric naming
parent
0db5680e
Changes
15
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
401 additions
and
84 deletions
+401
-84
libcaf_core/caf/telemetry/collector/prometheus.hpp
libcaf_core/caf/telemetry/collector/prometheus.hpp
+13
-0
libcaf_core/caf/telemetry/dbl_gauge.hpp
libcaf_core/caf/telemetry/dbl_gauge.hpp
+2
-0
libcaf_core/caf/telemetry/histogram.hpp
libcaf_core/caf/telemetry/histogram.hpp
+10
-3
libcaf_core/caf/telemetry/int_gauge.hpp
libcaf_core/caf/telemetry/int_gauge.hpp
+2
-0
libcaf_core/caf/telemetry/label.hpp
libcaf_core/caf/telemetry/label.hpp
+2
-0
libcaf_core/caf/telemetry/metric_family_impl.hpp
libcaf_core/caf/telemetry/metric_family_impl.hpp
+26
-2
libcaf_core/caf/telemetry/metric_impl.hpp
libcaf_core/caf/telemetry/metric_impl.hpp
+2
-0
libcaf_core/caf/telemetry/metric_registry.hpp
libcaf_core/caf/telemetry/metric_registry.hpp
+144
-28
libcaf_core/src/actor_registry.cpp
libcaf_core/src/actor_registry.cpp
+1
-1
libcaf_core/src/telemetry/collector/prometheus.cpp
libcaf_core/src/telemetry/collector/prometheus.cpp
+103
-3
libcaf_core/src/telemetry/label.cpp
libcaf_core/src/telemetry/label.cpp
+5
-0
libcaf_core/src/telemetry/metric_registry.cpp
libcaf_core/src/telemetry/metric_registry.cpp
+20
-5
libcaf_core/test/telemetry/collector/prometheus.cpp
libcaf_core/test/telemetry/collector/prometheus.cpp
+21
-7
libcaf_core/test/telemetry/metric_registry.cpp
libcaf_core/test/telemetry/metric_registry.cpp
+45
-30
libcaf_io/src/detail/prometheus_broker.cpp
libcaf_io/src/detail/prometheus_broker.cpp
+5
-5
No files found.
libcaf_core/caf/telemetry/collector/prometheus.hpp
View file @
4dc849fa
...
...
@@ -75,12 +75,22 @@ public:
void
operator
()(
const
metric_family
*
family
,
const
metric
*
instance
,
const
int_gauge
*
gauge
);
void
operator
()(
const
metric_family
*
family
,
const
metric
*
instance
,
const
dbl_histogram
*
val
);
void
operator
()(
const
metric_family
*
family
,
const
metric
*
instance
,
const
int_histogram
*
val
);
private:
/// Sets `current_family_` if not pointing to `family` already. When setting
/// the member variable, also writes meta information to `buf_`.
void
set_current_family
(
const
metric_family
*
family
,
string_view
prometheus_type
);
template
<
class
ValueType
>
void
append_histogram
(
const
metric_family
*
family
,
const
metric
*
instance
,
const
histogram
<
ValueType
>*
val
);
/// Stores the generated text output.
char_buffer
buf_
;
...
...
@@ -90,6 +100,9 @@ private:
/// Caches type information and help text for a metric.
std
::
unordered_map
<
const
metric_family
*
,
char_buffer
>
meta_info_
;
/// Caches type information and help text for a metric.
std
::
unordered_map
<
const
metric
*
,
std
::
vector
<
char_buffer
>>
virtual_metrics_
;
/// Caches which metric family is currently collected.
const
metric_family
*
current_family_
=
nullptr
;
...
...
libcaf_core/caf/telemetry/dbl_gauge.hpp
View file @
4dc849fa
...
...
@@ -35,6 +35,8 @@ public:
using
value_type
=
double
;
using
family_setting
=
unit_t
;
// -- constants --------------------------------------------------------------
static
constexpr
metric_type
runtime_type
=
metric_type
::
dbl_gauge
;
...
...
libcaf_core/caf/telemetry/histogram.hpp
View file @
4dc849fa
...
...
@@ -39,6 +39,8 @@ public:
using
gauge_type
=
gauge
<
value_type
>
;
using
family_setting
=
std
::
vector
<
value_type
>
;
struct
bucket_type
{
value_type
upper_bound
;
gauge_type
gauge
;
...
...
@@ -52,7 +54,7 @@ public:
// -- constructors, destructors, and assignment operators --------------------
histogram
(
span
<
const
value_type
>
upper_bounds
)
{
explicit
histogram
(
span
<
const
value_type
>
upper_bounds
)
{
using
limits
=
std
::
numeric_limits
<
value_type
>
;
CAF_ASSERT
(
std
::
is_sorted
(
upper_bounds
.
begin
(),
upper_bounds
.
end
()));
num_buckets_
=
upper_bounds
.
size
()
+
1
;
...
...
@@ -66,11 +68,15 @@ public:
buckets_
[
index
].
upper_bound
=
limits
::
max
();
}
histogram
(
std
::
initializer_list
<
value_type
>
upper_bounds
)
explicit
histogram
(
std
::
initializer_list
<
value_type
>
upper_bounds
)
:
histogram
(
make_span
(
upper_bounds
.
begin
(),
upper_bounds
.
size
()))
{
// nop
}
histogram
(
const
histogram
&
)
=
delete
;
histogram
&
operator
=
(
const
histogram
&
)
=
delete
;
~
histogram
()
{
delete
[]
buckets_
;
}
...
...
@@ -106,9 +112,10 @@ private:
gauge_type
sum_
;
};
///
///
Convenience alias for a histogram with value type `double`.
using
dbl_histogram
=
histogram
<
double
>
;
/// Convenience alias for a histogram with value type `int64_t`.
using
int_histogram
=
histogram
<
int64_t
>
;
}
// namespace caf::telemetry
libcaf_core/caf/telemetry/int_gauge.hpp
View file @
4dc849fa
...
...
@@ -35,6 +35,8 @@ public:
using
value_type
=
int64_t
;
using
family_setting
=
unit_t
;
// -- constants --------------------------------------------------------------
static
constexpr
metric_type
runtime_type
=
metric_type
::
int_gauge
;
...
...
libcaf_core/caf/telemetry/label.hpp
View file @
4dc849fa
...
...
@@ -59,6 +59,8 @@ public:
str_
.
size
()
-
name_length_
-
1
};
}
void
value
(
string_view
new_value
);
/// Returns the label in `name=value` notation.
const
std
::
string
&
str
()
const
noexcept
{
return
str_
;
...
...
libcaf_core/caf/telemetry/metric_family_impl.hpp
View file @
4dc849fa
...
...
@@ -36,9 +36,21 @@ namespace caf::telemetry {
template
<
class
Type
>
class
metric_family_impl
:
public
metric_family
{
public:
using
super
=
metric_family
;
using
impl_type
=
metric_impl
<
Type
>
;
using
metric_family
::
metric_family
;
using
extra_setting_type
=
typename
impl_type
::
family_setting
;
template
<
class
...
Ts
>
metric_family_impl
(
std
::
string
prefix
,
std
::
string
name
,
std
::
vector
<
std
::
string
>
label_names
,
std
::
string
helptext
,
std
::
string
unit
,
bool
is_sum
,
Ts
&&
...
xs
)
:
super
(
std
::
move
(
prefix
),
std
::
move
(
name
),
std
::
move
(
label_names
),
std
::
move
(
helptext
),
std
::
move
(
unit
),
is_sum
),
extra_setting_
(
std
::
forward
<
Ts
>
(
xs
)...)
{
// nop
}
metric_type
type
()
const
noexcept
override
{
return
Type
::
runtime_type
;
...
...
@@ -55,7 +67,12 @@ public:
if
(
m
==
metrics_
.
end
())
{
std
::
vector
<
label
>
cpy
{
labels
.
begin
(),
labels
.
end
()};
std
::
sort
(
cpy
.
begin
(),
cpy
.
end
());
m
=
metrics_
.
emplace
(
m
,
std
::
make_unique
<
impl_type
>
(
std
::
move
(
cpy
)));
std
::
unique_ptr
<
impl_type
>
ptr
;
if
constexpr
(
std
::
is_same
<
extra_setting_type
,
unit_t
>::
value
)
ptr
.
reset
(
new
impl_type
(
std
::
move
(
cpy
)));
else
ptr
.
reset
(
new
impl_type
(
std
::
move
(
cpy
),
extra_setting_
));
m
=
metrics_
.
emplace
(
m
,
std
::
move
(
ptr
));
}
return
std
::
addressof
(
m
->
get
()
->
impl
());
}
...
...
@@ -64,6 +81,12 @@ public:
return
get_or_add
(
span
<
const
label_view
>
{
labels
.
begin
(),
labels
.
size
()});
}
// -- properties --
const
auto
&
extra_setting
()
const
noexcept
{
return
extra_setting_
;
}
template
<
class
Collector
>
void
collect
(
Collector
&
collector
)
const
{
std
::
unique_lock
<
std
::
mutex
>
guard
{
mx_
};
...
...
@@ -72,6 +95,7 @@ public:
}
private:
extra_setting_type
extra_setting_
;
mutable
std
::
mutex
mx_
;
std
::
vector
<
std
::
unique_ptr
<
impl_type
>>
metrics_
;
};
...
...
libcaf_core/caf/telemetry/metric_impl.hpp
View file @
4dc849fa
...
...
@@ -31,6 +31,8 @@ namespace caf::telemetry {
template
<
class
Type
>
class
metric_impl
:
public
metric
{
public:
using
family_setting
=
typename
Type
::
family_setting
;
template
<
class
...
Ts
>
metric_impl
(
std
::
vector
<
label
>
labels
,
Ts
&&
...
xs
)
:
metric
(
std
::
move
(
labels
)),
impl_
(
std
::
forward
<
Ts
>
(
xs
)...)
{
...
...
libcaf_core/caf/telemetry/metric_registry.hpp
View file @
4dc849fa
...
...
@@ -25,7 +25,10 @@
#include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp"
#include "caf/raise_error.hpp"
#include "caf/string_view.hpp"
#include "caf/telemetry/gauge.hpp"
#include "caf/telemetry/histogram.hpp"
#include "caf/telemetry/metric_family_impl.hpp"
namespace
caf
::
telemetry
{
...
...
@@ -49,8 +52,8 @@ public:
// -- factories --------------------------------------------------------------
/// Returns a
metric family. Creates the family lazily if necessary, but fails
/// if the full name already belongs to a different family.
/// Returns a
gauge metric family. Creates the family lazily if necessary, but
///
fails
if the full name already belongs to a different family.
/// @param prefix The prefix (namespace) this family belongs to. Usually the
/// application or protocol name, e.g., `http`. The prefix `caf`
/// as well as prefixes starting with an underscore are
...
...
@@ -64,41 +67,120 @@ public:
/// @param is_sum Setting this to `true` indicates that this metric adds
/// something up to a total, where only the total value is of
/// interest. For example, the total number of HTTP requests.
template
<
class
Type
>
metric_family_impl
<
Type
>*
family
(
string_view
prefix
,
string_view
name
,
span
<
const
string_view
>
label_names
,
string_view
helptext
,
string_view
unit
=
"1"
,
bool
is_sum
=
false
)
{
using
family_type
=
metric_family_impl
<
Type
>
;
template
<
class
ValueType
=
int64_t
>
metric_family_impl
<
gauge
<
ValueType
>>*
gauge_family
(
string_view
prefix
,
string_view
name
,
span
<
const
string_view
>
label_names
,
string_view
helptext
,
string_view
unit
=
"1"
,
bool
is_sum
=
false
)
{
using
gauge_type
=
gauge
<
ValueType
>
;
using
family_type
=
metric_family_impl
<
gauge_type
>
;
std
::
unique_lock
<
std
::
mutex
>
guard
{
families_mx_
};
if
(
auto
ptr
=
fetch
(
prefix
,
name
))
{
assert_properties
(
ptr
,
Type
::
runtime_type
,
label_names
,
unit
,
is_sum
);
assert_properties
(
ptr
,
gauge_type
::
runtime_type
,
label_names
,
unit
,
is_sum
);
return
static_cast
<
family_type
*>
(
ptr
);
}
auto
ptr
=
std
::
make_unique
<
family_type
>
(
to_string
(
prefix
),
to_string
(
name
),
to_sorted_vec
(
label_names
),
to_string
(
helptext
),
to_string
(
unit
),
is_sum
);
auto
&
families
=
container_by_type
<
T
ype
>
();
auto
&
families
=
container_by_type
<
gauge_t
ype
>
();
families
.
emplace_back
(
std
::
move
(
ptr
));
return
families
.
back
().
get
();
}
/// @copydoc family
template
<
class
Type
>
metric_family_impl
<
Type
>*
family
(
string_view
prefix
,
string_view
name
,
std
::
initializer_list
<
string_view
>
label_names
,
string_view
helptext
,
/// @copydoc gauge_family
template
<
class
ValueType
=
int64_t
>
metric_family_impl
<
gauge
<
ValueType
>>*
gauge_family
(
string_view
prefix
,
string_view
name
,
std
::
initializer_list
<
string_view
>
label_names
,
string_view
helptext
,
string_view
unit
=
"1"
,
bool
is_sum
=
false
)
{
auto
lbl_span
=
make_span
(
label_names
.
begin
(),
label_names
.
size
());
return
gauge_family
<
ValueType
>
(
prefix
,
name
,
lbl_span
,
helptext
,
unit
,
is_sum
);
}
/// Returns a gauge metric singleton, i.e., the single instance of a family
/// without label dimensions. Creates all objects lazily if necessary, but
/// fails if the full name already belongs to a different family.
/// @param prefix The prefix (namespace) this family belongs to. Usually the
/// application or protocol name, e.g., `http`. The prefix `caf`
/// as well as prefixes starting with an underscore are
/// reserved.
/// @param name The human-readable name of the metric, e.g., `requests`.
/// @param helptext Short explanation of the metric.
/// @param unit Unit of measurement. Please use base units such as `bytes` or
/// `seconds` (prefer lowercase). The pseudo-unit `1` identifies
/// dimensionless counts.
/// @param is_sum Setting this to `true` indicates that this metric adds
/// something up to a total, where only the total value is of
/// interest. For example, the total number of HTTP requests.
template
<
class
ValueType
=
int64_t
>
gauge
<
ValueType
>*
gauge_singleton
(
string_view
prefix
,
string_view
name
,
string_view
helptext
,
string_view
unit
=
"1"
,
bool
is_sum
=
false
)
{
return
family
<
Type
>
(
prefix
,
name
,
span
<
const
string_view
>
{
label_names
.
begin
(),
label_names
.
size
()},
span
<
const
string_view
>
lbls
;
auto
fptr
=
gauge_family
<
ValueType
>
(
prefix
,
name
,
lbls
,
helptext
,
unit
,
is_sum
);
return
fptr
->
get_or_add
({});
}
/// Returns a histogram metric family. Creates the family lazily if necessary,
/// but fails if the full name already belongs to a different family.
/// @param prefix The prefix (namespace) this family belongs to. Usually the
/// application or protocol name, e.g., `http`. The prefix `caf`
/// as well as prefixes starting with an underscore are
/// reserved.
/// @param name The human-readable name of the metric, e.g., `requests`.
/// @param label_names Names for all label dimensions of the metric.
/// @param upper_bounds Upper bounds for the metric buckets.
/// @param helptext Short explanation of the metric.
/// @param unit Unit of measurement. Please use base units such as `bytes` or
/// `seconds` (prefer lowercase). The pseudo-unit `1` identifies
/// dimensionless counts.
/// @param is_sum Setting this to `true` indicates that this metric adds
/// something up to a total, where only the total value is of
/// interest. For example, the total number of HTTP requests.
template
<
class
ValueType
=
int64_t
>
metric_family_impl
<
histogram
<
ValueType
>>*
histogram_family
(
string_view
prefix
,
string_view
name
,
span
<
const
string_view
>
label_names
,
span
<
const
typename
histogram
<
ValueType
>::
value_type
>
upper_bounds
,
string_view
helptext
,
string_view
unit
=
"1"
,
bool
is_sum
=
false
)
{
if
(
upper_bounds
.
empty
())
CAF_RAISE_ERROR
(
"at least one bucket must exist"
);
using
histogram_type
=
histogram
<
ValueType
>
;
using
family_type
=
metric_family_impl
<
histogram_type
>
;
std
::
unique_lock
<
std
::
mutex
>
guard
{
families_mx_
};
if
(
auto
ptr
=
fetch
(
prefix
,
name
))
{
assert_histogram_properties
(
ptr
,
histogram_type
::
runtime_type
,
label_names
,
upper_bounds
,
unit
,
is_sum
);
return
static_cast
<
family_type
*>
(
ptr
);
}
auto
ptr
=
std
::
make_unique
<
family_type
>
(
to_string
(
prefix
),
to_string
(
name
),
to_sorted_vec
(
label_names
),
to_string
(
helptext
),
to_string
(
unit
),
is_sum
,
upper_bounds
.
begin
(),
upper_bounds
.
end
());
auto
&
families
=
container_by_type
<
histogram_type
>
();
families
.
emplace_back
(
std
::
move
(
ptr
));
return
families
.
back
().
get
();
}
/// @copydoc gauge_family
template
<
class
ValueType
=
int64_t
>
metric_family_impl
<
histogram
<
ValueType
>>*
histogram_family
(
string_view
prefix
,
string_view
name
,
std
::
initializer_list
<
string_view
>
label_names
,
span
<
const
typename
histogram
<
ValueType
>::
value_type
>
upper_bounds
,
string_view
helptext
,
string_view
unit
=
"1"
,
bool
is_sum
=
false
)
{
auto
lbl_span
=
make_span
(
label_names
.
begin
(),
label_names
.
size
());
return
histogram_family
<
ValueType
>
(
prefix
,
name
,
lbl_span
,
upper_bounds
,
helptext
,
unit
,
is_sum
);
}
/// Returns a
metric singleton, i.e., the single instance of a family without
///
label dimensions. Creates all objects lazily if necessary, but fails if
/// the full name already belongs to a different family.
/// Returns a
histogram metric singleton, i.e., the single instance of a
///
family without label dimensions. Creates all objects lazily if necessary,
///
but fails if
the full name already belongs to a different family.
/// @param prefix The prefix (namespace) this family belongs to. Usually the
/// application or protocol name, e.g., `http`. The prefix `caf`
/// as well as prefixes starting with an underscore are
...
...
@@ -111,10 +193,14 @@ public:
/// @param is_sum Setting this to `true` indicates that this metric adds
/// something up to a total, where only the total value is of
/// interest. For example, the total number of HTTP requests.
template
<
class
Type
>
Type
*
singleton
(
string_view
prefix
,
string_view
name
,
string_view
helptext
,
template
<
class
ValueType
=
int64_t
>
histogram
<
ValueType
>*
histogram_singleton
(
string_view
prefix
,
string_view
name
,
string_view
helptext
,
span
<
const
ValueType
>
upper_bounds
,
string_view
unit
=
"1"
,
bool
is_sum
=
false
)
{
auto
fptr
=
family
<
Type
>
(
prefix
,
name
,
{},
helptext
,
unit
,
is_sum
);
span
<
const
string_view
>
lbls
;
auto
fptr
=
histogram_family
<
ValueType
>
(
prefix
,
name
,
lbls
,
upper_bounds
,
helptext
,
unit
,
is_sum
);
return
fptr
->
get_or_add
({});
}
...
...
@@ -127,6 +213,10 @@ public:
ptr
->
collect
(
collector
);
for
(
auto
&
ptr
:
int_gauges_
)
ptr
->
collect
(
collector
);
for
(
auto
&
ptr
:
dbl_histograms_
)
ptr
->
collect
(
collector
);
for
(
auto
&
ptr
:
int_histograms_
)
ptr
->
collect
(
collector
);
}
private:
...
...
@@ -144,11 +234,23 @@ private:
return
result
;
}
void
assert_properties
(
metric_family
*
ptr
,
metric_type
type
,
void
assert_properties
(
const
metric_family
*
ptr
,
metric_type
type
,
span
<
const
string_view
>
label_names
,
string_view
unit
,
bool
is_sum
);
void
assert_equal
(
metric_family
*
old_ptr
,
metric_family
*
new_ptr
);
template
<
class
ValueType
>
void
assert_histogram_properties
(
const
metric_family
*
ptr
,
metric_type
type
,
span
<
const
string_view
>
label_names
,
span
<
const
ValueType
>
upper_bounds
,
string_view
unit
,
bool
is_sum
)
{
assert_properties
(
ptr
,
type
,
label_names
,
unit
,
is_sum
);
using
family_type
=
metric_family_impl
<
histogram
<
ValueType
>>
;
auto
dptr
=
static_cast
<
const
family_type
*>
(
ptr
);
auto
&
xs
=
dptr
->
extra_setting
();
if
(
!
std
::
equal
(
xs
.
begin
(),
xs
.
end
(),
upper_bounds
.
begin
(),
upper_bounds
.
end
()))
CAF_RAISE_ERROR
(
"full name with different bucket settings found"
);
}
template
<
class
Type
>
metric_family_container
<
Type
>&
container_by_type
();
...
...
@@ -157,6 +259,8 @@ private:
metric_family_container
<
telemetry
::
dbl_gauge
>
dbl_gauges_
;
metric_family_container
<
telemetry
::
int_gauge
>
int_gauges_
;
metric_family_container
<
telemetry
::
dbl_histogram
>
dbl_histograms_
;
metric_family_container
<
telemetry
::
int_histogram
>
int_histograms_
;
};
template
<
>
...
...
@@ -171,4 +275,16 @@ metric_registry::container_by_type<int_gauge>() {
return
int_gauges_
;
}
template
<
>
inline
metric_registry
::
metric_family_container
<
int_histogram
>&
metric_registry
::
container_by_type
<
int_histogram
>
()
{
return
int_histograms_
;
}
template
<
>
inline
metric_registry
::
metric_family_container
<
dbl_histogram
>&
metric_registry
::
container_by_type
<
dbl_histogram
>
()
{
return
dbl_histograms_
;
}
}
// namespace caf::telemetry
libcaf_core/src/actor_registry.cpp
View file @
4dc849fa
...
...
@@ -49,7 +49,7 @@ actor_registry::~actor_registry() {
}
actor_registry
::
actor_registry
(
actor_system
&
sys
)
:
system_
(
sys
)
{
running_
=
sys
.
telemetry
().
singleton
<
telemetry
::
int_gauge
>
(
running_
=
sys
.
telemetry
().
gauge_singleton
(
"caf"
,
"running_actors"
,
"Number of currently running actors."
);
}
...
...
libcaf_core/src/telemetry/collector/prometheus.cpp
View file @
4dc849fa
...
...
@@ -48,6 +48,10 @@ struct ms_timestamp {
ms_timestamp
&
operator
=
(
const
ms_timestamp
&
)
=
default
;
};
struct
underline_to_hyphen
{
string_view
str
;
};
void
append
(
prometheus
::
char_buffer
&
)
{
// End of recursion.
}
...
...
@@ -55,6 +59,9 @@ void append(prometheus::char_buffer&) {
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
,
string_view
,
Ts
&&
...);
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
,
underline_to_hyphen
,
Ts
&&
...);
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
,
char
,
Ts
&&
...);
...
...
@@ -68,18 +75,31 @@ append(prometheus::char_buffer& buf, T val, Ts&&... xs);
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
,
const
metric_family
*
,
Ts
&&
...);
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
,
const
std
::
vector
<
label
>&
,
Ts
&&
...);
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
,
const
metric
*
,
Ts
&&
...);
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
,
ms_timestamp
,
Ts
&&
...);
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
,
const
prometheus
::
char_buffer
&
,
Ts
&&
...);
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
buf
,
string_view
str
,
Ts
&&
...
xs
)
{
buf
.
insert
(
buf
.
end
(),
str
.
begin
(),
str
.
end
());
append
(
buf
,
std
::
forward
<
Ts
>
(
xs
)...);
}
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
buf
,
underline_to_hyphen
x
,
Ts
&&
...
xs
)
{
for
(
auto
c
:
x
.
str
)
buf
.
emplace_back
(
c
!=
'-'
?
c
:
'_'
);
append
(
buf
,
std
::
forward
<
Ts
>
(
xs
)...);
}
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
buf
,
char
ch
,
Ts
&&
...
xs
)
{
buf
.
emplace_back
(
ch
);
...
...
@@ -111,7 +131,8 @@ append(prometheus::char_buffer& buf, T val, Ts&&... xs) {
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
buf
,
const
metric_family
*
family
,
Ts
&&
...
xs
)
{
append
(
buf
,
family
->
prefix
(),
'_'
,
family
->
name
());
append
(
buf
,
underline_to_hyphen
{
family
->
prefix
()},
'_'
,
underline_to_hyphen
{
family
->
name
()});
if
(
family
->
unit
()
!=
"1"
_sv
)
append
(
buf
,
'_'
,
family
->
unit
());
if
(
family
->
is_sum
())
...
...
@@ -120,8 +141,8 @@ void append(prometheus::char_buffer& buf, const metric_family* family,
}
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
buf
,
const
metric
*
instance
,
Ts
&&
...
xs
)
{
const
auto
&
labels
=
instance
->
labels
();
void
append
(
prometheus
::
char_buffer
&
buf
,
const
std
::
vector
<
label
>&
labels
,
Ts
&&
...
xs
)
{
if
(
!
labels
.
empty
())
{
append
(
buf
,
'{'
);
auto
i
=
labels
.
begin
();
...
...
@@ -133,12 +154,24 @@ void append(prometheus::char_buffer& buf, const metric* instance, Ts&&... xs) {
append
(
buf
,
std
::
forward
<
Ts
>
(
xs
)...);
}
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
buf
,
const
metric
*
instance
,
Ts
&&
...
xs
)
{
append
(
buf
,
instance
->
labels
(),
std
::
forward
<
Ts
>
(
xs
)...);
}
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
buf
,
ms_timestamp
ts
,
Ts
&&
...
xs
)
{
append
(
buf
,
ts
.
value
);
append
(
buf
,
std
::
forward
<
Ts
>
(
xs
)...);
}
template
<
class
...
Ts
>
void
append
(
prometheus
::
char_buffer
&
buf
,
const
prometheus
::
char_buffer
&
x
,
Ts
&&
...
xs
)
{
buf
.
insert
(
buf
.
end
(),
x
.
begin
(),
x
.
end
());
append
(
buf
,
std
::
forward
<
Ts
>
(
xs
)...);
}
}
// namespace
string_view
prometheus
::
collect_from
(
const
metric_registry
&
registry
,
...
...
@@ -170,6 +203,16 @@ void prometheus::operator()(const metric_family* family, const metric* instance,
'\n'
);
}
void
prometheus
::
operator
()(
const
metric_family
*
family
,
const
metric
*
instance
,
const
dbl_histogram
*
val
)
{
append_histogram
(
family
,
instance
,
val
);
}
void
prometheus
::
operator
()(
const
metric_family
*
family
,
const
metric
*
instance
,
const
int_histogram
*
val
)
{
append_histogram
(
family
,
instance
,
val
);
}
void
prometheus
::
set_current_family
(
const
metric_family
*
family
,
string_view
prometheus_type
)
{
if
(
current_family_
==
family
)
...
...
@@ -185,4 +228,61 @@ void prometheus::set_current_family(const metric_family* family,
buf_
.
insert
(
buf_
.
end
(),
i
->
second
.
begin
(),
i
->
second
.
end
());
}
namespace
{
template
<
class
ValueType
>
auto
make_virtual_metrics
(
const
metric_family
*
family
,
const
metric
*
instance
,
const
histogram
<
ValueType
>*
val
)
{
std
::
vector
<
prometheus
::
char_buffer
>
result
;
auto
add_result
=
[
&
](
auto
&&
...
xs
)
{
result
.
emplace_back
();
append
(
result
.
back
(),
std
::
forward
<
decltype
(
xs
)
>
(
xs
)...);
};
auto
buckets
=
val
->
buckets
();
auto
num_buckets
=
buckets
.
size
();
CAF_ASSERT
(
num_buckets
>
1
);
auto
labels
=
instance
->
labels
();
labels
.
emplace_back
(
"le"
,
""
);
result
.
reserve
(
num_buckets
+
2
);
size_t
index
=
0
;
// Create bucket variable names for 1..N-1.
for
(;
index
<
num_buckets
-
1
;
++
index
)
{
auto
upper_bound
=
std
::
to_string
(
buckets
[
index
].
upper_bound
);
labels
.
back
().
value
(
upper_bound
);
add_result
(
family
,
"_bucket"
,
labels
,
' '
);
}
// The last bucket always sets le="+Inf"
labels
.
back
().
value
(
"+Inf"
);
add_result
(
family
,
"_bucket"
,
labels
,
' '
);
labels
.
pop_back
();
add_result
(
family
,
"_sum"
,
labels
,
' '
);
add_result
(
family
,
"_count"
,
labels
,
' '
);
return
result
;
}
}
// namespace
template
<
class
ValueType
>
void
prometheus
::
append_histogram
(
const
metric_family
*
family
,
const
metric
*
instance
,
const
histogram
<
ValueType
>*
val
)
{
auto
i
=
virtual_metrics_
.
find
(
instance
);
if
(
i
==
virtual_metrics_
.
end
())
{
auto
metrics
=
make_virtual_metrics
(
family
,
instance
,
val
);
i
=
virtual_metrics_
.
emplace
(
instance
,
std
::
move
(
metrics
)).
first
;
}
set_current_family
(
family
,
"histogram"
);
auto
&
vm
=
i
->
second
;
auto
buckets
=
val
->
buckets
();
size_t
index
=
0
;
for
(;
index
<
buckets
.
size
()
-
1
;
++
index
)
{
append
(
buf_
,
vm
[
index
],
buckets
[
index
].
gauge
.
value
(),
' '
,
ms_timestamp
{
now_
},
'\n'
);
}
auto
count
=
buckets
[
index
].
gauge
.
value
();
append
(
buf_
,
vm
[
index
],
count
,
' '
,
ms_timestamp
{
now_
},
'\n'
);
append
(
buf_
,
vm
[
++
index
],
val
->
sum
(),
' '
,
ms_timestamp
{
now_
},
'\n'
);
append
(
buf_
,
vm
[
++
index
],
count
,
' '
,
ms_timestamp
{
now_
},
'\n'
);
}
}
// namespace caf::telemetry::collector
libcaf_core/src/telemetry/label.cpp
View file @
4dc849fa
...
...
@@ -33,6 +33,11 @@ label::label(const label_view& view) : label(view.name(), view.value()) {
// nop
}
void
label
::
value
(
string_view
new_value
)
{
str_
.
erase
(
name_length_
+
1
);
str_
.
insert
(
str_
.
end
(),
new_value
.
begin
(),
new_value
.
end
());
}
int
label
::
compare
(
const
label
&
x
)
const
noexcept
{
return
str_
.
compare
(
x
.
str
());
}
...
...
libcaf_core/src/telemetry/metric_registry.cpp
View file @
4dc849fa
...
...
@@ -19,13 +19,21 @@
#include "caf/telemetry/metric_registry.hpp"
#include "caf/config.hpp"
#include "caf/raise_error.hpp"
#include "caf/telemetry/dbl_gauge.hpp"
#include "caf/telemetry/int_gauge.hpp"
#include "caf/telemetry/metric_family_impl.hpp"
#include "caf/telemetry/metric_impl.hpp"
#include "caf/telemetry/metric_type.hpp"
namespace
{
template
<
class
Range1
,
class
Range2
>
bool
equals
(
Range1
&&
xs
,
Range2
&&
ys
)
{
return
std
::
equal
(
xs
.
begin
(),
xs
.
end
(),
ys
.
begin
(),
ys
.
end
());
}
}
// namespace
namespace
caf
::
telemetry
{
metric_registry
::
metric_registry
()
{
...
...
@@ -38,19 +46,26 @@ metric_registry::~metric_registry() {
metric_family
*
metric_registry
::
fetch
(
const
string_view
&
prefix
,
const
string_view
&
name
)
{
auto
matches
=
[
&
](
const
auto
&
ptr
)
{
auto
eq
=
[
&
](
const
auto
&
ptr
)
{
return
ptr
->
prefix
()
==
prefix
&&
ptr
->
name
()
==
name
;
};
if
(
auto
i
=
std
::
find_if
(
dbl_gauges_
.
begin
(),
dbl_gauges_
.
end
(),
matches
);
if
(
auto
i
=
std
::
find_if
(
dbl_gauges_
.
begin
(),
dbl_gauges_
.
end
(),
eq
);
i
!=
dbl_gauges_
.
end
())
return
i
->
get
();
if
(
auto
i
=
std
::
find_if
(
int_gauges_
.
begin
(),
int_gauges_
.
end
(),
matches
);
if
(
auto
i
=
std
::
find_if
(
int_gauges_
.
begin
(),
int_gauges_
.
end
(),
eq
);
i
!=
int_gauges_
.
end
())
return
i
->
get
();
if
(
auto
i
=
std
::
find_if
(
dbl_histograms_
.
begin
(),
dbl_histograms_
.
end
(),
eq
);
i
!=
dbl_histograms_
.
end
())
return
i
->
get
();
if
(
auto
i
=
std
::
find_if
(
int_histograms_
.
begin
(),
int_histograms_
.
end
(),
eq
);
i
!=
int_histograms_
.
end
())
return
i
->
get
();
return
nullptr
;
}
void
metric_registry
::
assert_properties
(
metric_family
*
ptr
,
metric_type
type
,
void
metric_registry
::
assert_properties
(
const
metric_family
*
ptr
,
metric_type
type
,
span
<
const
string_view
>
label_names
,
string_view
unit
,
bool
is_sum
)
{
auto
labels_match
=
[
&
]
{
...
...
libcaf_core/test/telemetry/collector/prometheus.cpp
View file @
4dc849fa
...
...
@@ -32,7 +32,6 @@ using namespace caf::telemetry;
namespace
{
struct
fixture
{
using
ig
=
int_gauge
;
collector
::
prometheus
exporter
;
metric_registry
registry
;
};
...
...
@@ -42,16 +41,23 @@ struct fixture {
CAF_TEST_FIXTURE_SCOPE
(
prometheus_tests
,
fixture
)
CAF_TEST
(
the
Prometheus
collector
generates
text
output
)
{
auto
fb
=
registry
.
family
<
ig
>
(
"foo"
,
"bar"
,
{},
"Some value without labels."
,
"seconds"
);
auto
sv
=
registry
.
family
<
ig
>
(
"some"
,
"value"
,
{
"a"
,
"b"
},
auto
fb
=
registry
.
gauge_family
(
"foo"
,
"bar"
,
{}
,
"Some value without labels."
,
"seconds"
);
auto
sv
=
registry
.
gauge_family
(
"some"
,
"value"
,
{
"a"
,
"b"
},
"Some (total) value with two labels."
,
"1"
,
true
);
auto
ov
=
registry
.
family
<
ig
>
(
"other"
,
"value"
,
{
"x"
},
""
,
"seconds"
,
true
);
auto
ov
=
registry
.
gauge_family
(
"other"
,
"value"
,
{
"x"
},
""
,
"seconds"
,
true
);
std
::
vector
<
int64_t
>
upper_bounds
{
1
,
2
,
4
};
auto
sr
=
registry
.
histogram_family
(
"some"
,
"request-duration"
,
{
"x"
},
upper_bounds
,
"Some help."
,
"seconds"
);
fb
->
get_or_add
({})
->
value
(
123
);
sv
->
get_or_add
({{
"a"
,
"1"
},
{
"b"
,
"2"
}})
->
value
(
12
);
sv
->
get_or_add
({{
"b"
,
"1"
},
{
"a"
,
"2"
}})
->
value
(
21
);
ov
->
get_or_add
({{
"x"
,
"true"
}})
->
value
(
31337
);
auto
h
=
sr
->
get_or_add
({{
"x"
,
"get"
}});
h
->
observe
(
3
);
h
->
observe
(
4
);
h
->
observe
(
7
);
CAF_CHECK_EQUAL
(
exporter
.
collect_from
(
registry
,
42
),
R"(# HELP foo_bar_seconds Some value without labels.
# TYPE foo_bar_seconds gauge
...
...
@@ -62,6 +68,14 @@ some_value_total{a="1",b="2"} 12 42000
some_value_total{a="2",b="1"} 21 42000
# TYPE other_value_seconds_total gauge
other_value_seconds_total{x="true"} 31337 42000
# HELP some_request_duration_seconds Some help.
# TYPE some_request_duration_seconds histogram
some_request_duration_seconds_bucket{x="get",le="1"} 0 42000
some_request_duration_seconds_bucket{x="get",le="2"} 0 42000
some_request_duration_seconds_bucket{x="get",le="4"} 2 42000
some_request_duration_seconds_bucket{x="get",le="+Inf"} 1 42000
some_request_duration_seconds_sum{x="get"} 14 42000
some_request_duration_seconds_count{x="get"} 1 42000
)"
_sv
);
CAF_MESSAGE
(
"multiple runs generate the same output"
);
std
::
string
res1
;
...
...
libcaf_core/test/telemetry/metric_registry.cpp
View file @
4dc849fa
...
...
@@ -48,17 +48,24 @@ struct test_collector {
result
+=
std
::
to_string
(
wrapped
->
value
());
}
template
<
class
T
>
void
operator
()(
const
metric_family
*
family
,
const
metric
*
instance
,
const
histogram
<
T
>*
wrapped
)
{
concat
(
family
,
instance
);
result
+=
std
::
to_string
(
wrapped
->
sum
());
}
void
concat
(
const
metric_family
*
family
,
const
metric
*
instance
)
{
result
+=
'\n'
;
result
+=
family
->
prefix
();
result
+=
'
_
'
;
result
+=
'
.
'
;
result
+=
family
->
name
();
if
(
family
->
unit
()
!=
"1"
)
{
result
+=
'
_
'
;
result
+=
'
.
'
;
result
+=
family
->
unit
();
}
if
(
family
->
is_sum
())
result
+=
"
_
total"
;
result
+=
"
.
total"
;
if
(
!
instance
->
labels
().
empty
())
{
result
+=
'{'
;
auto
i
=
instance
->
labels
().
begin
();
...
...
@@ -81,7 +88,6 @@ struct test_collector {
};
struct
fixture
{
using
ig
=
int_gauge
;
metric_registry
registry
;
test_collector
collector
;
};
...
...
@@ -91,8 +97,11 @@ struct fixture {
CAF_TEST_FIXTURE_SCOPE
(
metric_registry_tests
,
fixture
)
CAF_TEST
(
registries
lazily
create
metrics
)
{
auto
f
=
registry
.
family
<
ig
>
(
"caf"
,
"running_actors"
,
{
"var1"
,
"var2"
},
std
::
vector
<
int64_t
>
upper_bounds
{
1
,
2
,
4
,
8
};
auto
f
=
registry
.
gauge_family
(
"caf"
,
"running-actors"
,
{
"var1"
,
"var2"
},
"How many actors are currently running?"
);
auto
g
=
registry
.
histogram_family
(
"caf"
,
"response-time"
,
{
"var1"
,
"var2"
},
upper_bounds
,
"How long take requests?"
);
std
::
vector
<
label_view
>
v1
{{
"var1"
,
"foo"
},
{
"var2"
,
"bar"
}};
std
::
vector
<
label_view
>
v1_reversed
{{
"var2"
,
"bar"
},
{
"var1"
,
"foo"
}};
std
::
vector
<
label_view
>
v2
{{
"var1"
,
"bar"
},
{
"var2"
,
"foo"
}};
...
...
@@ -103,27 +112,33 @@ CAF_TEST(registries lazily create metrics) {
CAF_CHECK_EQUAL
(
f
->
get_or_add
(
v1_reversed
)
->
value
(),
42
);
CAF_CHECK_EQUAL
(
f
->
get_or_add
(
v2
)
->
value
(),
23
);
CAF_CHECK_EQUAL
(
f
->
get_or_add
(
v2_reversed
)
->
value
(),
23
);
g
->
get_or_add
(
v1
)
->
observe
(
3
);
g
->
get_or_add
(
v2
)
->
observe
(
7
);
CAF_CHECK_EQUAL
(
g
->
get_or_add
(
v1
)
->
sum
(),
3
);
CAF_CHECK_EQUAL
(
g
->
get_or_add
(
v1_reversed
)
->
sum
(),
3
);
CAF_CHECK_EQUAL
(
g
->
get_or_add
(
v2
)
->
sum
(),
7
);
CAF_CHECK_EQUAL
(
g
->
get_or_add
(
v2_reversed
)
->
sum
(),
7
);
}
CAF_TEST
(
registries
allow
users
to
collect
all
registered
metrics
)
{
auto
fb
=
registry
.
family
<
ig
>
(
"foo"
,
"bar"
,
{},
"Some value without labels."
,
"seconds"
);
auto
sv
=
registry
.
family
<
ig
>
(
"some"
,
"value"
,
{
"a"
,
"b"
},
auto
fb
=
registry
.
gauge_family
(
"foo"
,
"bar"
,
{}
,
"Some value without labels."
,
"seconds"
);
auto
sv
=
registry
.
gauge_family
(
"some"
,
"value"
,
{
"a"
,
"b"
},
"Some (total) value with two labels."
,
"1"
,
true
);
auto
ov
=
registry
.
family
<
ig
>
(
"other"
,
"value"
,
{
"x"
},
auto
ov
=
registry
.
gauge_family
(
"other"
,
"value"
,
{
"x"
},
"Some (total) seconds with one label."
,
"seconds"
,
true
);
auto
ra
=
registry
.
family
<
ig
>
(
"caf"
,
"running_
actors"
,
{
"node"
},
auto
ra
=
registry
.
gauge_family
(
"caf"
,
"running-
actors"
,
{
"node"
},
"How many actors are running?"
);
auto
ms
=
registry
.
family
<
ig
>
(
"caf"
,
"mailbox_
size"
,
{
"name"
},
auto
ms
=
registry
.
gauge_family
(
"caf"
,
"mailbox-
size"
,
{
"name"
},
"How full is the mailbox?"
);
CAF_MESSAGE
(
"the registry always returns the same family object"
);
CAF_CHECK_EQUAL
(
fb
,
registry
.
family
<
ig
>
(
"foo"
,
"bar"
,
{},
""
,
"seconds"
));
CAF_CHECK_EQUAL
(
sv
,
registry
.
family
<
ig
>
(
"some"
,
"value"
,
{
"a"
,
"b"
},
""
,
"1
"
,
true
));
CAF_CHECK_EQUAL
(
sv
,
registry
.
family
<
ig
>
(
"some"
,
"value"
,
{
"b"
,
"a"
},
""
,
"1
"
,
true
));
CAF_CHECK_EQUAL
(
fb
,
registry
.
gauge_family
(
"foo"
,
"bar"
,
{},
""
,
"seconds"
));
CAF_CHECK_EQUAL
(
sv
,
registry
.
gauge_family
(
"some"
,
"value"
,
{
"a"
,
"b"
},
"
"
,
"1"
,
true
));
CAF_CHECK_EQUAL
(
sv
,
registry
.
gauge_family
(
"some"
,
"value"
,
{
"b"
,
"a"
},
"
"
,
"1"
,
true
));
CAF_MESSAGE
(
"families always return the same metric object for given labels"
);
CAF_CHECK_EQUAL
(
fb
->
get_or_add
({}),
fb
->
get_or_add
({}));
CAF_CHECK_EQUAL
(
sv
->
get_or_add
({{
"a"
,
"1"
},
{
"b"
,
"2"
}}),
...
...
@@ -138,13 +153,13 @@ CAF_TEST(registries allow users to collect all registered metrics) {
ms
->
get_or_add
({{
"name"
,
"parser"
}})
->
value
(
12
);
registry
.
collect
(
collector
);
CAF_CHECK_EQUAL
(
collector
.
result
,
R"(
foo
_bar_
seconds 123
some
_value_
total{a="1",b="2"} 12
some
_value_
total{a="2",b="1"} 21
other
_value_seconds_
total{x="true"} 31337
caf
_running_
actors{node="localhost"} 42
caf
_mailbox_
size{name="printer"} 3
caf
_mailbox_
size{name="parser"} 12)"
);
foo
.bar.
seconds 123
some
.value.
total{a="1",b="2"} 12
some
.value.
total{a="2",b="1"} 21
other
.value.seconds.
total{x="true"} 31337
caf
.running-
actors{node="localhost"} 42
caf
.mailbox-
size{name="printer"} 3
caf
.mailbox-
size{name="parser"} 12)"
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
libcaf_io/src/detail/prometheus_broker.cpp
View file @
4dc849fa
...
...
@@ -192,11 +192,11 @@ prometheus_broker::prometheus_broker(actor_config& cfg) : io::broker(cfg) {
using
telemetry
::
dbl_gauge
;
using
telemetry
::
int_gauge
;
auto
&
reg
=
system
().
telemetry
();
cpu_time_
=
reg
.
singleton
<
dbl_gaug
e
>
(
cpu_time_
=
reg
.
gauge_singleton
<
doubl
e
>
(
"process"
,
"cpu"
,
"Total user and system CPU time spent."
,
"seconds"
,
true
);
mem_size_
=
reg
.
singleton
<
int_gauge
>
(
"process"
,
"resident_memory"
,
mem_size_
=
reg
.
gauge_singleton
(
"process"
,
"resident_memory"
,
"Resident memory size."
,
"bytes"
);
virt_mem_size_
=
reg
.
singleton
<
int_gauge
>
(
"process"
,
"virtual_memory"
,
virt_mem_size_
=
reg
.
gauge_singleton
(
"process"
,
"virtual_memory"
,
"Virtual memory size."
,
"bytes"
);
#endif // HAS_PROCESS_METRICS
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment