Skip to content
This repository was archived by the owner on Jul 31, 2023. It is now read-only.

Commit 30b28a3

Browse files
Introduce Metrics (#127)
1 parent a31bc28 commit 30b28a3

File tree

8 files changed

+375
-4
lines changed

8 files changed

+375
-4
lines changed

elvis.config

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
filter => "*.erl",
88
ignore => ["src/oc_trace_pb.erl", "src/oc_trace_config_pb.erl"],
99
rules => [{elvis_style, god_modules, #{ignore => [ocp]}},
10-
{elvis_style, no_debug_call, #{ignore => [oc_reporter_stdout, oc_stat_exporter_stdout]}},
10+
{elvis_style, no_debug_call, #{ignore => [oc_reporter_stdout,
11+
oc_stat_exporter_stdout]}},
1112
{elvis_style, dont_repeat_yourself, #{min_complexity => 20}},
1213
{elvis_style, line_length, #{limit => 120}},
1314
{elvis_style, state_record_and_type, disable},
@@ -18,7 +19,8 @@
1819
{elvis_style, invalid_dynamic_call, #{ignore => [oc_reporter_sequential, %% loops over reporters
1920
oc_stat_view, %% calls aggragtions
2021
oc_stat_measure, %% calls generated modules
21-
oc_stat_exporter %% loops over exporters
22+
oc_stat_exporter, %% loops over exporters,
23+
oc_producer_registry %% loops over metric producers
2224
]}}],
2325
ruleset => erl_files
2426
},

include/oc_metrics.hrl

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
-type oc_string() :: iodata().
2+
-type oc_float() :: float() | integer() | infinity | '-infinity' | nan.
3+
-type oc_double() :: float() | integer() | infinity | '-infinity' | nan.
4+
-type oc_int64() :: integer().
5+
-type oc_uint64() :: non_neg_integer().
6+
-type oc_int32() :: integer().
7+
-type oc_uint32() :: integer().
8+
9+
-type registry() :: atom().
10+
11+
%% Defines a label key associated with a metric descriptor.
12+
-record(oc_label_key,
13+
{key = <<>> :: oc_string(),
14+
description = <<>> :: oc_string()
15+
}).
16+
17+
-type oc_label_key() :: #oc_label_key{}.
18+
19+
%% Represents the value of label
20+
%% @type oc_label_value(v) = #oc_label_value{value = binary() | iolist(),
21+
%% present = boolean()}
22+
-record(oc_label_value,
23+
{value :: oc_string() | undefined, %% the value of the label
24+
present :: boolean() %% if false the value field is ignored and considered not set;
25+
%% This is used to differentiate a missing label from an empty string.
26+
}).
27+
28+
-type oc_label_value() :: #oc_label_value{}.
29+
30+
-record(oc_explicit_bucket_options,
31+
{bounds = [] :: [oc_double()]
32+
}).
33+
34+
-type oc_explicit_bucket_options() :: #oc_explicit_bucket_options{}.
35+
36+
-record(exemplar,
37+
{value = 0.0 :: oc_double(),
38+
timestamp = undefined :: wts:timestamp() | undefined,
39+
attachments = #{} :: #{oc_string() := oc_string()}
40+
}).
41+
42+
-type exemplar() :: #exemplar{}.
43+
44+
-record(oc_bucket,
45+
{count = 0 :: oc_int64(),
46+
exemplar = undefined :: oc_metrics:exemplar() | undefined
47+
}).
48+
49+
-type oc_bucket() :: #oc_bucket{}.
50+
51+
-record(oc_distribution,
52+
{count = 0 :: oc_int32(),
53+
sum = 0.0 :: oc_double(),
54+
sum_of_squared_deviation = 0.0 :: oc_double(),
55+
bucket_options = undefined :: oc_explicit_bucket_options() | undefined,
56+
buckets = undefined :: [oc_bucket()] | undefined
57+
}).
58+
59+
-type oc_distribution() :: #oc_distribution{}.
60+
61+
-record(oc_value_at_percentile,
62+
{percentile = 0.0 :: oc_double(),
63+
value = 0.0 :: oc_double()
64+
}).
65+
66+
-type oc_value_at_percentile() :: #oc_value_at_percentile{}.
67+
68+
-record(oc_snapshot,
69+
{count = undefined :: oc_int64() | undefined,
70+
sum = undefined :: oc_double() | undefined,
71+
percentile_values = [] :: [oc_value_at_percentile()] | undefined
72+
}).
73+
74+
-type oc_snapshot() :: #oc_snapshot{}.
75+
76+
-record(oc_summary,
77+
{count = 0 :: oc_int64(),
78+
sum = 0.0 :: oc_double(),
79+
snapshot = undefined :: oc_snapshot() | undefined
80+
}).
81+
82+
-type oc_summary() :: #oc_summary{}.
83+
84+
-record(oc_point,
85+
{timestamp = undefined :: wts:timestamp() | undefined,
86+
value :: oc_int64() | oc_double() |
87+
oc_distribution() | oc_summary()
88+
}).
89+
90+
-type oc_point() :: #oc_point{}.
91+
92+
-record(oc_time_series,
93+
{start_timestamp = undefined :: wts:timestamp() | undefined,
94+
label_values = [] :: [oc_label_value()],
95+
points = [] :: [oc_point()]
96+
}).
97+
98+
-type oc_time_series() :: #oc_time_series{}.
99+
-record(oc_metric_descriptor,
100+
{name = <<>> :: oc_string(),
101+
description = <<>> :: oc_string(),
102+
unit = <<"1">> :: oc_string(),
103+
type = 'UNSPECIFIED' :: 'UNSPECIFIED' |
104+
'GAUGE_INT64' |
105+
'GAUGE_DOUBLE' |
106+
'GAUGE_DISTRIBUTION' |
107+
'CUMULATIVE_INT64' |
108+
'CUMULATIVE_DOUBLE' |
109+
'CUMULATIVE_DISTRIBUTION' |
110+
'SUMMARY',
111+
label_keys = [] :: [oc_label_key()] %% The label keys associated with the metric descriptor.
112+
}).
113+
114+
-type oc_metric_descriptor() :: #oc_metric_descriptor{}.
115+
116+
-record(oc_resource,
117+
{type = <<>> :: oc_string(),
118+
labels = #{} :: #{oc_string() := oc_string()}
119+
}).
120+
121+
-type oc_resource() :: #oc_resource{}.
122+
123+
-record(oc_metric,
124+
{descriptor :: oc_metric_descriptor() | oc_string(),
125+
timeseries = [] :: [oc_time_series()],
126+
resource = undefined :: oc_resource() | undefined
127+
}).
128+
129+
-type oc_metric() :: #oc_metric{}.
130+
131+
-type metric_callback() ::
132+
fun((oc_producer_registry:registry(), oc_metric()) -> any()).

src/oc_producer.erl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
%% @doc
2+
%% Producer is a source of metrics.
3+
%% @end
4+
-module(oc_producer).
5+
6+
-include("oc_metrics.hrl").
7+
8+
%% @doc
9+
%% Read should call `Callback' with the current values of all metrics
10+
%% supported by this metric provider.
11+
%% The metrics should be unique for each combination of name and resource.
12+
%% @end
13+
-callback read(Registry, Callback) -> ok when
14+
Registry :: oc_producer_registry:registry(),
15+
Callback :: metric_callback().
16+
17+
-callback cleanup(Registry) -> ok when
18+
Registry :: oc_producer_registry:registry().
19+
20+
-optional_callbacks([cleanup/1]).

src/oc_producer_registry.erl

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
%% @doc
2+
%% Registry maintains a set of metric producers for exporting.
3+
%% Most users will rely on the DefaultRegistry.
4+
%% @end
5+
-module(oc_producer_registry).
6+
7+
-export([read_to_list/0,
8+
read_to_list/1,
9+
10+
read_all/1,
11+
read_all/2,
12+
13+
add_producer/1,
14+
add_producer/2,
15+
16+
remove_producer/1,
17+
remove_producer/2]).
18+
19+
%% @equiv read_all(default)
20+
read_all(Callback) ->
21+
read_all(default, Callback).
22+
23+
%% @doc
24+
%% Calls `Callback' for each metric produced by the metric producers in the `Registry'.
25+
%% @end
26+
read_all(Registry, Callback) ->
27+
[Producer:read(Registry, Callback) || {_, Producer} <- ets:lookup(?MODULE, Registry)],
28+
ok.
29+
30+
%%
31+
read_to_list() ->
32+
read_to_list(default).
33+
34+
read_to_list(Registry) ->
35+
Ref = make_ref(),
36+
try
37+
Callback = fun (M) ->
38+
put(Ref, [M|get_list(Ref)])
39+
end,
40+
read_all(Registry, Callback),
41+
42+
get_list(Ref)
43+
after
44+
erase(Ref)
45+
end.
46+
47+
%% @equiv(default, Producer)
48+
add_producer(Producer) ->
49+
add_producer(default, Producer).
50+
51+
%% @doc
52+
%% Adds `Producer' to the `Registry'.
53+
%% @end
54+
add_producer(Registry, Producer) ->
55+
ets:insert(?MODULE, {Registry, Producer}),
56+
ok.
57+
58+
%% @equiv remove_producer(default, Producer)
59+
remove_producer(Producer) ->
60+
remove_producer(default, Producer).
61+
62+
remove_producer(Registry, Producer) ->
63+
ets:delete_object(?MODULE, {Registry, Producer}),
64+
case erlang:function_exported(Producer, cleanup, 1) of
65+
true -> Producer:cleanup(Registry);
66+
_ -> ok
67+
end,
68+
ok.
69+
70+
get_list(Key) ->
71+
case get(Key) of
72+
undefined ->
73+
[];
74+
Value ->
75+
Value
76+
end.

src/oc_self_producer.erl

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
%% @doc
2+
%% Produces metrics for internal state like spans queue size, views count, etc.
3+
-module(oc_self_producer).
4+
5+
-export([read/2]).
6+
7+
-include("oc_metrics.hrl").
8+
-include("opencensus.hrl").
9+
10+
read(_Registry, Callback) ->
11+
spans_buffer_metrics(Callback).
12+
13+
spans_buffer_metrics(Callback) ->
14+
{Count, Bytes} = oc_span_sweeper:storage_size(),
15+
Callback(#oc_metric{descriptor = #oc_metric_descriptor{
16+
name = "oc_span_buffer_bytes",
17+
description = "Size of the spans ETS table",
18+
type = 'GAUGE_INT64'
19+
},
20+
timeseries = [#oc_time_series{
21+
points = [#oc_point{timestamp = wts:timestamp(),
22+
value = Bytes}]
23+
}
24+
]
25+
}),
26+
Callback(#oc_metric{descriptor = #oc_metric_descriptor{
27+
name = "oc_span_buffer_size",
28+
description = "Count of spans in the ETS table",
29+
type = 'GAUGE_INT64'
30+
},
31+
timeseries = [#oc_time_series{
32+
points = [#oc_point{timestamp = wts:timestamp(),
33+
value = Count}]
34+
}
35+
]
36+
}).

src/oc_span_sweeper.erl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
code_change/4,
2525
terminate/3]).
2626

27+
-export([storage_size/0]).
28+
2729
-include("opencensus.hrl").
2830
-include("oc_logger.hrl").
2931

@@ -32,6 +34,9 @@
3234
ttl :: integer() | infinity,
3335
storage_size :: integer() | infinity}).
3436

37+
storage_size() ->
38+
{ets:info(?SPAN_TAB, size), ets:info(?SPAN_TAB, memory) * erlang:system_info({wordsize, external})}.
39+
3540
start_link() ->
3641
gen_statem:start_link({local, ?MODULE}, ?MODULE, [], []).
3742

@@ -78,7 +83,7 @@ do_gc(#data{strategy=Strategy,
7883
ttl=TTL,
7984
storage_size=MaxSize}) ->
8085

81-
StorageSize = ets:info(?SPAN_TAB, memory) * erlang:system_info({wordsize, external}),
86+
{_, StorageSize} = storage_size(),
8287

8388
if
8489
StorageSize >= 2 * MaxSize ->

src/opencensus_app.erl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,9 @@ maybe_init_ets() ->
3838
{read_concurrency, true}, {keypos, #span.span_id}]);
3939
_ ->
4040
ok
41-
end.
41+
end,
42+
43+
ets:new(oc_producer_registry, [bag, named_table, public, {write_concurrency, true},
44+
{read_concurrency, true}]),
45+
46+
oc_producer_registry:add_producer(oc_self_producer).

0 commit comments

Comments
 (0)