chore: merge 'upstream/master'
This commit is contained in:
commit
6ead09b28d
|
@ -82,20 +82,8 @@ jobs:
|
||||||
echo "ct-host=${CT_HOST}" | tee -a $GITHUB_OUTPUT
|
echo "ct-host=${CT_HOST}" | tee -a $GITHUB_OUTPUT
|
||||||
echo "ct-docker=${CT_DOCKER}" | tee -a $GITHUB_OUTPUT
|
echo "ct-docker=${CT_DOCKER}" | tee -a $GITHUB_OUTPUT
|
||||||
|
|
||||||
build_slim_packages:
|
|
||||||
if: ${{ needs.prepare.outputs.release != 'true' }}
|
|
||||||
needs:
|
|
||||||
- prepare
|
|
||||||
uses: ./.github/workflows/build_slim_packages.yaml
|
|
||||||
with:
|
|
||||||
runner: ${{ needs.prepare.outputs.runner }}
|
|
||||||
builder: ${{ needs.prepare.outputs.builder }}
|
|
||||||
builder_vsn: ${{ needs.prepare.outputs.builder_vsn }}
|
|
||||||
otp_vsn: ${{ needs.prepare.outputs.otp_vsn }}
|
|
||||||
elixir_vsn: ${{ needs.prepare.outputs.elixir_vsn }}
|
|
||||||
|
|
||||||
build_packages:
|
build_packages:
|
||||||
if: ${{ needs.prepare.outputs.release == 'true' }}
|
if: needs.prepare.outputs.release == 'true'
|
||||||
needs:
|
needs:
|
||||||
- prepare
|
- prepare
|
||||||
uses: ./.github/workflows/build_packages.yaml
|
uses: ./.github/workflows/build_packages.yaml
|
||||||
|
@ -109,7 +97,7 @@ jobs:
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
build_and_push_docker_images:
|
build_and_push_docker_images:
|
||||||
if: ${{ needs.prepare.outputs.release == 'true' }}
|
if: needs.prepare.outputs.release == 'true'
|
||||||
needs:
|
needs:
|
||||||
- prepare
|
- prepare
|
||||||
uses: ./.github/workflows/build_and_push_docker_images.yaml
|
uses: ./.github/workflows/build_and_push_docker_images.yaml
|
||||||
|
@ -124,7 +112,20 @@ jobs:
|
||||||
runner: ${{ needs.prepare.outputs.runner }}
|
runner: ${{ needs.prepare.outputs.runner }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
build_slim_packages:
|
||||||
|
if: needs.prepare.outputs.release != 'true'
|
||||||
|
needs:
|
||||||
|
- prepare
|
||||||
|
uses: ./.github/workflows/build_slim_packages.yaml
|
||||||
|
with:
|
||||||
|
runner: ${{ needs.prepare.outputs.runner }}
|
||||||
|
builder: ${{ needs.prepare.outputs.builder }}
|
||||||
|
builder_vsn: ${{ needs.prepare.outputs.builder_vsn }}
|
||||||
|
otp_vsn: ${{ needs.prepare.outputs.otp_vsn }}
|
||||||
|
elixir_vsn: ${{ needs.prepare.outputs.elixir_vsn }}
|
||||||
|
|
||||||
compile:
|
compile:
|
||||||
|
if: needs.prepare.outputs.release != 'true'
|
||||||
runs-on: ${{ needs.prepare.outputs.runner }}
|
runs-on: ${{ needs.prepare.outputs.runner }}
|
||||||
container: ${{ needs.prepare.outputs.builder }}
|
container: ${{ needs.prepare.outputs.builder }}
|
||||||
needs:
|
needs:
|
||||||
|
@ -157,6 +158,7 @@ jobs:
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
run_test_cases:
|
run_test_cases:
|
||||||
|
if: needs.prepare.outputs.release != 'true'
|
||||||
needs:
|
needs:
|
||||||
- prepare
|
- prepare
|
||||||
- compile
|
- compile
|
||||||
|
@ -169,6 +171,7 @@ jobs:
|
||||||
ct-docker: ${{ needs.prepare.outputs.ct-docker }}
|
ct-docker: ${{ needs.prepare.outputs.ct-docker }}
|
||||||
|
|
||||||
run_conf_tests:
|
run_conf_tests:
|
||||||
|
if: needs.prepare.outputs.release != 'true'
|
||||||
needs:
|
needs:
|
||||||
- prepare
|
- prepare
|
||||||
- compile
|
- compile
|
||||||
|
@ -178,6 +181,7 @@ jobs:
|
||||||
builder: ${{ needs.prepare.outputs.builder }}
|
builder: ${{ needs.prepare.outputs.builder }}
|
||||||
|
|
||||||
static_checks:
|
static_checks:
|
||||||
|
if: needs.prepare.outputs.release != 'true'
|
||||||
needs:
|
needs:
|
||||||
- prepare
|
- prepare
|
||||||
- compile
|
- compile
|
||||||
|
|
|
@ -264,7 +264,7 @@ jobs:
|
||||||
path: _packages/${{ matrix.profile }}/
|
path: _packages/${{ matrix.profile }}/
|
||||||
|
|
||||||
publish_artifacts:
|
publish_artifacts:
|
||||||
runs-on: ${{ inputs.runner }}
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
- mac
|
- mac
|
||||||
- linux
|
- linux
|
||||||
|
@ -280,7 +280,7 @@ jobs:
|
||||||
name: ${{ matrix.profile }}
|
name: ${{ matrix.profile }}
|
||||||
path: packages/${{ matrix.profile }}
|
path: packages/${{ matrix.profile }}
|
||||||
- name: install dos2unix
|
- name: install dos2unix
|
||||||
run: apt-get update && apt install -y dos2unix
|
run: sudo apt-get update && sudo apt install -y dos2unix
|
||||||
- name: get packages
|
- name: get packages
|
||||||
run: |
|
run: |
|
||||||
set -eu
|
set -eu
|
||||||
|
@ -300,7 +300,7 @@ jobs:
|
||||||
env:
|
env:
|
||||||
PROFILE: ${{ matrix.profile }}
|
PROFILE: ${{ matrix.profile }}
|
||||||
run: |
|
run: |
|
||||||
set -e -u
|
set -eu
|
||||||
if [ $PROFILE = 'emqx' ]; then
|
if [ $PROFILE = 'emqx' ]; then
|
||||||
s3dir='emqx-ce'
|
s3dir='emqx-ce'
|
||||||
elif [ $PROFILE = 'emqx-enterprise' ]; then
|
elif [ $PROFILE = 'emqx-enterprise' ]; then
|
||||||
|
|
|
@ -679,4 +679,7 @@ end).
|
||||||
-define(THROW_FRAME_ERROR(Reason), erlang:throw({?FRAME_PARSE_ERROR, Reason})).
|
-define(THROW_FRAME_ERROR(Reason), erlang:throw({?FRAME_PARSE_ERROR, Reason})).
|
||||||
-define(THROW_SERIALIZE_ERROR(Reason), erlang:throw({?FRAME_SERIALIZE_ERROR, Reason})).
|
-define(THROW_SERIALIZE_ERROR(Reason), erlang:throw({?FRAME_SERIALIZE_ERROR, Reason})).
|
||||||
|
|
||||||
|
-define(MAX_PAYLOAD_FORMAT_SIZE, 1024).
|
||||||
|
-define(MAX_PAYLOAD_FORMAT_LIMIT(Bin), (byte_size(Bin) =< ?MAX_PAYLOAD_FORMAT_SIZE)).
|
||||||
|
|
||||||
-endif.
|
-endif.
|
||||||
|
|
|
@ -55,8 +55,6 @@
|
||||||
format/2
|
format/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([encode_hex/1]).
|
|
||||||
|
|
||||||
-define(TYPE_NAMES,
|
-define(TYPE_NAMES,
|
||||||
{'CONNECT', 'CONNACK', 'PUBLISH', 'PUBACK', 'PUBREC', 'PUBREL', 'PUBCOMP', 'SUBSCRIBE',
|
{'CONNECT', 'CONNACK', 'PUBLISH', 'PUBACK', 'PUBREC', 'PUBREL', 'PUBCOMP', 'SUBSCRIBE',
|
||||||
'SUBACK', 'UNSUBSCRIBE', 'UNSUBACK', 'PINGREQ', 'PINGRESP', 'DISCONNECT', 'AUTH'}
|
'SUBACK', 'UNSUBSCRIBE', 'UNSUBACK', 'PINGREQ', 'PINGRESP', 'DISCONNECT', 'AUTH'}
|
||||||
|
@ -616,9 +614,20 @@ format_password(undefined) -> "";
|
||||||
format_password(<<>>) -> "";
|
format_password(<<>>) -> "";
|
||||||
format_password(_Password) -> "******".
|
format_password(_Password) -> "******".
|
||||||
|
|
||||||
format_payload(Payload, text) -> ["Payload=", io_lib:format("~ts", [Payload])];
|
format_payload(Payload, text) when ?MAX_PAYLOAD_FORMAT_LIMIT(Payload) ->
|
||||||
format_payload(Payload, hex) -> ["Payload(hex)=", encode_hex(Payload)];
|
["Payload=", unicode:characters_to_list(Payload)];
|
||||||
format_payload(_, hidden) -> "Payload=******".
|
format_payload(Payload, hex) when ?MAX_PAYLOAD_FORMAT_LIMIT(Payload) ->
|
||||||
|
["Payload(hex)=", binary:encode_hex(Payload)];
|
||||||
|
format_payload(_, hidden) ->
|
||||||
|
"Payload=******";
|
||||||
|
format_payload(<<Part:100, _/binary>> = Payload, _) ->
|
||||||
|
[
|
||||||
|
"Payload=",
|
||||||
|
Part,
|
||||||
|
"... The ",
|
||||||
|
integer_to_list(byte_size(Payload) - 100),
|
||||||
|
" bytes of this log are truncated"
|
||||||
|
].
|
||||||
|
|
||||||
i(true) -> 1;
|
i(true) -> 1;
|
||||||
i(false) -> 0;
|
i(false) -> 0;
|
||||||
|
@ -641,71 +650,3 @@ format_topic_filters(Filters) ->
|
||||||
),
|
),
|
||||||
"]"
|
"]"
|
||||||
].
|
].
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
%% Hex encoding functions
|
|
||||||
%% Copy from binary:encode_hex/1 (was only introduced in OTP24).
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
-define(HEX(X), (hex(X)):16).
|
|
||||||
-compile({inline, [hex/1]}).
|
|
||||||
-spec encode_hex(Bin) -> Bin2 when
|
|
||||||
Bin :: binary(),
|
|
||||||
Bin2 :: <<_:_*16>>.
|
|
||||||
encode_hex(Data) when byte_size(Data) rem 8 =:= 0 ->
|
|
||||||
<<
|
|
||||||
<<?HEX(A), ?HEX(B), ?HEX(C), ?HEX(D), ?HEX(E), ?HEX(F), ?HEX(G), ?HEX(H)>>
|
|
||||||
|| <<A, B, C, D, E, F, G, H>> <= Data
|
|
||||||
>>;
|
|
||||||
encode_hex(Data) when byte_size(Data) rem 7 =:= 0 ->
|
|
||||||
<<
|
|
||||||
<<?HEX(A), ?HEX(B), ?HEX(C), ?HEX(D), ?HEX(E), ?HEX(F), ?HEX(G)>>
|
|
||||||
|| <<A, B, C, D, E, F, G>> <= Data
|
|
||||||
>>;
|
|
||||||
encode_hex(Data) when byte_size(Data) rem 6 =:= 0 ->
|
|
||||||
<<<<?HEX(A), ?HEX(B), ?HEX(C), ?HEX(D), ?HEX(E), ?HEX(F)>> || <<A, B, C, D, E, F>> <= Data>>;
|
|
||||||
encode_hex(Data) when byte_size(Data) rem 5 =:= 0 ->
|
|
||||||
<<<<?HEX(A), ?HEX(B), ?HEX(C), ?HEX(D), ?HEX(E)>> || <<A, B, C, D, E>> <= Data>>;
|
|
||||||
encode_hex(Data) when byte_size(Data) rem 4 =:= 0 ->
|
|
||||||
<<<<?HEX(A), ?HEX(B), ?HEX(C), ?HEX(D)>> || <<A, B, C, D>> <= Data>>;
|
|
||||||
encode_hex(Data) when byte_size(Data) rem 3 =:= 0 ->
|
|
||||||
<<<<?HEX(A), ?HEX(B), ?HEX(C)>> || <<A, B, C>> <= Data>>;
|
|
||||||
encode_hex(Data) when byte_size(Data) rem 2 =:= 0 ->
|
|
||||||
<<<<?HEX(A), ?HEX(B)>> || <<A, B>> <= Data>>;
|
|
||||||
encode_hex(Data) when is_binary(Data) ->
|
|
||||||
<<<<?HEX(N)>> || <<N>> <= Data>>;
|
|
||||||
encode_hex(Bin) ->
|
|
||||||
erlang:error(badarg, [Bin]).
|
|
||||||
|
|
||||||
hex(X) ->
|
|
||||||
element(
|
|
||||||
X + 1,
|
|
||||||
{16#3030, 16#3031, 16#3032, 16#3033, 16#3034, 16#3035, 16#3036, 16#3037, 16#3038, 16#3039,
|
|
||||||
16#3041, 16#3042, 16#3043, 16#3044, 16#3045, 16#3046, 16#3130, 16#3131, 16#3132,
|
|
||||||
16#3133, 16#3134, 16#3135, 16#3136, 16#3137, 16#3138, 16#3139, 16#3141, 16#3142,
|
|
||||||
16#3143, 16#3144, 16#3145, 16#3146, 16#3230, 16#3231, 16#3232, 16#3233, 16#3234,
|
|
||||||
16#3235, 16#3236, 16#3237, 16#3238, 16#3239, 16#3241, 16#3242, 16#3243, 16#3244,
|
|
||||||
16#3245, 16#3246, 16#3330, 16#3331, 16#3332, 16#3333, 16#3334, 16#3335, 16#3336,
|
|
||||||
16#3337, 16#3338, 16#3339, 16#3341, 16#3342, 16#3343, 16#3344, 16#3345, 16#3346,
|
|
||||||
16#3430, 16#3431, 16#3432, 16#3433, 16#3434, 16#3435, 16#3436, 16#3437, 16#3438,
|
|
||||||
16#3439, 16#3441, 16#3442, 16#3443, 16#3444, 16#3445, 16#3446, 16#3530, 16#3531,
|
|
||||||
16#3532, 16#3533, 16#3534, 16#3535, 16#3536, 16#3537, 16#3538, 16#3539, 16#3541,
|
|
||||||
16#3542, 16#3543, 16#3544, 16#3545, 16#3546, 16#3630, 16#3631, 16#3632, 16#3633,
|
|
||||||
16#3634, 16#3635, 16#3636, 16#3637, 16#3638, 16#3639, 16#3641, 16#3642, 16#3643,
|
|
||||||
16#3644, 16#3645, 16#3646, 16#3730, 16#3731, 16#3732, 16#3733, 16#3734, 16#3735,
|
|
||||||
16#3736, 16#3737, 16#3738, 16#3739, 16#3741, 16#3742, 16#3743, 16#3744, 16#3745,
|
|
||||||
16#3746, 16#3830, 16#3831, 16#3832, 16#3833, 16#3834, 16#3835, 16#3836, 16#3837,
|
|
||||||
16#3838, 16#3839, 16#3841, 16#3842, 16#3843, 16#3844, 16#3845, 16#3846, 16#3930,
|
|
||||||
16#3931, 16#3932, 16#3933, 16#3934, 16#3935, 16#3936, 16#3937, 16#3938, 16#3939,
|
|
||||||
16#3941, 16#3942, 16#3943, 16#3944, 16#3945, 16#3946, 16#4130, 16#4131, 16#4132,
|
|
||||||
16#4133, 16#4134, 16#4135, 16#4136, 16#4137, 16#4138, 16#4139, 16#4141, 16#4142,
|
|
||||||
16#4143, 16#4144, 16#4145, 16#4146, 16#4230, 16#4231, 16#4232, 16#4233, 16#4234,
|
|
||||||
16#4235, 16#4236, 16#4237, 16#4238, 16#4239, 16#4241, 16#4242, 16#4243, 16#4244,
|
|
||||||
16#4245, 16#4246, 16#4330, 16#4331, 16#4332, 16#4333, 16#4334, 16#4335, 16#4336,
|
|
||||||
16#4337, 16#4338, 16#4339, 16#4341, 16#4342, 16#4343, 16#4344, 16#4345, 16#4346,
|
|
||||||
16#4430, 16#4431, 16#4432, 16#4433, 16#4434, 16#4435, 16#4436, 16#4437, 16#4438,
|
|
||||||
16#4439, 16#4441, 16#4442, 16#4443, 16#4444, 16#4445, 16#4446, 16#4530, 16#4531,
|
|
||||||
16#4532, 16#4533, 16#4534, 16#4535, 16#4536, 16#4537, 16#4538, 16#4539, 16#4541,
|
|
||||||
16#4542, 16#4543, 16#4544, 16#4545, 16#4546, 16#4630, 16#4631, 16#4632, 16#4633,
|
|
||||||
16#4634, 16#4635, 16#4636, 16#4637, 16#4638, 16#4639, 16#4641, 16#4642, 16#4643,
|
|
||||||
16#4644, 16#4645, 16#4646}
|
|
||||||
).
|
|
||||||
|
|
|
@ -37,7 +37,8 @@
|
||||||
setstat/2,
|
setstat/2,
|
||||||
setstat/3,
|
setstat/3,
|
||||||
statsfun/1,
|
statsfun/1,
|
||||||
statsfun/2
|
statsfun/2,
|
||||||
|
names/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([
|
-export([
|
||||||
|
@ -157,6 +158,28 @@ getstats() ->
|
||||||
_ -> ets:tab2list(?TAB)
|
_ -> ets:tab2list(?TAB)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
names() ->
|
||||||
|
[
|
||||||
|
emqx_connections_count,
|
||||||
|
emqx_connections_max,
|
||||||
|
emqx_live_connections_count,
|
||||||
|
emqx_live_connections_max,
|
||||||
|
emqx_sessions_count,
|
||||||
|
emqx_sessions_max,
|
||||||
|
emqx_topics_count,
|
||||||
|
emqx_topics_max,
|
||||||
|
emqx_suboptions_count,
|
||||||
|
emqx_suboptions_max,
|
||||||
|
emqx_subscribers_count,
|
||||||
|
emqx_subscribers_max,
|
||||||
|
emqx_subscriptions_count,
|
||||||
|
emqx_subscriptions_max,
|
||||||
|
emqx_subscriptions_shared_count,
|
||||||
|
emqx_subscriptions_shared_max,
|
||||||
|
emqx_retained_count,
|
||||||
|
emqx_retained_max
|
||||||
|
].
|
||||||
|
|
||||||
%% @doc Get stats by name.
|
%% @doc Get stats by name.
|
||||||
-spec getstat(atom()) -> non_neg_integer().
|
-spec getstat(atom()) -> non_neg_integer().
|
||||||
getstat(Name) ->
|
getstat(Name) ->
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
%% limitations under the License.
|
%% limitations under the License.
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-module(emqx_trace_formatter).
|
-module(emqx_trace_formatter).
|
||||||
|
-include("emqx_mqtt.hrl").
|
||||||
|
|
||||||
-export([format/2]).
|
-export([format/2]).
|
||||||
-export([format_meta_map/1]).
|
-export([format_meta_map/1]).
|
||||||
|
@ -68,10 +69,20 @@ weight({K, _}) -> {1, K}.
|
||||||
format_packet(undefined, _) -> "";
|
format_packet(undefined, _) -> "";
|
||||||
format_packet(Packet, Encode) -> emqx_packet:format(Packet, Encode).
|
format_packet(Packet, Encode) -> emqx_packet:format(Packet, Encode).
|
||||||
|
|
||||||
format_payload(undefined, _) -> "";
|
format_payload(undefined, _) ->
|
||||||
format_payload(Payload, text) -> io_lib:format("~ts", [Payload]);
|
"";
|
||||||
format_payload(Payload, hex) -> emqx_packet:encode_hex(Payload);
|
format_payload(_, hidden) ->
|
||||||
format_payload(_, hidden) -> "******".
|
"******";
|
||||||
|
format_payload(Payload, text) when ?MAX_PAYLOAD_FORMAT_LIMIT(Payload) ->
|
||||||
|
unicode:characters_to_list(Payload);
|
||||||
|
format_payload(Payload, hex) when ?MAX_PAYLOAD_FORMAT_LIMIT(Payload) -> binary:encode_hex(Payload);
|
||||||
|
format_payload(<<Part:100, _/binary>> = Payload, _) ->
|
||||||
|
[
|
||||||
|
Part,
|
||||||
|
"... The ",
|
||||||
|
integer_to_list(byte_size(Payload) - 100),
|
||||||
|
" bytes of this log are truncated"
|
||||||
|
].
|
||||||
|
|
||||||
to_iolist(Atom) when is_atom(Atom) -> atom_to_list(Atom);
|
to_iolist(Atom) when is_atom(Atom) -> atom_to_list(Atom);
|
||||||
to_iolist(Int) when is_integer(Int) -> integer_to_list(Int);
|
to_iolist(Int) when is_integer(Int) -> integer_to_list(Int);
|
||||||
|
|
|
@ -274,7 +274,6 @@ t_load_state(_Config) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
t_client_event(_Config) ->
|
t_client_event(_Config) ->
|
||||||
application:set_env(emqx, allow_anonymous, true),
|
|
||||||
ClientId = <<"client-test">>,
|
ClientId = <<"client-test">>,
|
||||||
Now = erlang:system_time(second),
|
Now = erlang:system_time(second),
|
||||||
Name = <<"test_client_id_event">>,
|
Name = <<"test_client_id_event">>,
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
emqx_psk_schema,
|
emqx_psk_schema,
|
||||||
emqx_limiter_schema,
|
emqx_limiter_schema,
|
||||||
emqx_slow_subs_schema,
|
emqx_slow_subs_schema,
|
||||||
|
emqx_otel_schema,
|
||||||
emqx_mgmt_api_key_schema
|
emqx_mgmt_api_key_schema
|
||||||
]).
|
]).
|
||||||
%% 1 million default ports counter
|
%% 1 million default ports counter
|
||||||
|
|
|
@ -24,7 +24,12 @@
|
||||||
redbug,
|
redbug,
|
||||||
xmerl,
|
xmerl,
|
||||||
{hocon, load},
|
{hocon, load},
|
||||||
telemetry
|
telemetry,
|
||||||
|
{opentelemetry, load},
|
||||||
|
{opentelemetry_api, load},
|
||||||
|
{opentelemetry_experimental, load},
|
||||||
|
{opentelemetry_api_experimental, load},
|
||||||
|
{opentelemetry_exporter, load}
|
||||||
],
|
],
|
||||||
%% must always be of type `load'
|
%% must always be of type `load'
|
||||||
common_business_apps =>
|
common_business_apps =>
|
||||||
|
@ -68,6 +73,7 @@
|
||||||
emqx_redis,
|
emqx_redis,
|
||||||
emqx_mysql,
|
emqx_mysql,
|
||||||
emqx_plugins,
|
emqx_plugins,
|
||||||
|
emqx_opentelemetry,
|
||||||
quicer,
|
quicer,
|
||||||
bcrypt,
|
bcrypt,
|
||||||
jq,
|
jq,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{application, emqx_management, [
|
{application, emqx_management, [
|
||||||
{description, "EMQX Management API and CLI"},
|
{description, "EMQX Management API and CLI"},
|
||||||
% strict semver, bump manually!
|
% strict semver, bump manually!
|
||||||
{vsn, "5.0.26"},
|
{vsn, "5.0.27"},
|
||||||
{modules, []},
|
{modules, []},
|
||||||
{registered, [emqx_management_sup]},
|
{registered, [emqx_management_sup]},
|
||||||
{applications, [kernel, stdlib, emqx_plugins, minirest, emqx, emqx_ctl, emqx_bridge_http]},
|
{applications, [kernel, stdlib, emqx_plugins, minirest, emqx, emqx_ctl, emqx_bridge_http]},
|
||||||
|
|
|
@ -107,7 +107,8 @@
|
||||||
%% Common Table API
|
%% Common Table API
|
||||||
-export([
|
-export([
|
||||||
default_row_limit/0,
|
default_row_limit/0,
|
||||||
vm_stats/0
|
vm_stats/0,
|
||||||
|
vm_stats/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-elvis([{elvis_style, god_modules, disable}]).
|
-elvis([{elvis_style, god_modules, disable}]).
|
||||||
|
@ -185,22 +186,33 @@ stopped_node_info(Node) ->
|
||||||
{Node, #{node => Node, node_status => 'stopped', role => core}}.
|
{Node, #{node => Node, node_status => 'stopped', role => core}}.
|
||||||
|
|
||||||
vm_stats() ->
|
vm_stats() ->
|
||||||
Idle =
|
Idle = vm_stats('cpu.idle'),
|
||||||
case cpu_sup:util([detailed]) of
|
|
||||||
%% Not support for Windows
|
|
||||||
{_, 0, 0, _} -> 0;
|
|
||||||
{_Num, _Use, IdleList, _} -> proplists:get_value(idle, IdleList, 0)
|
|
||||||
end,
|
|
||||||
RunQueue = erlang:statistics(run_queue),
|
|
||||||
{MemUsedRatio, MemTotal} = get_sys_memory(),
|
{MemUsedRatio, MemTotal} = get_sys_memory(),
|
||||||
[
|
[
|
||||||
{run_queue, RunQueue},
|
{run_queue, vm_stats('run.queue')},
|
||||||
{cpu_idle, Idle},
|
{cpu_idle, Idle},
|
||||||
{cpu_use, 100 - Idle},
|
{cpu_use, 100 - Idle},
|
||||||
{total_memory, MemTotal},
|
{total_memory, MemTotal},
|
||||||
{used_memory, erlang:round(MemTotal * MemUsedRatio)}
|
{used_memory, erlang:round(MemTotal * MemUsedRatio)}
|
||||||
].
|
].
|
||||||
|
|
||||||
|
vm_stats('cpu.idle') ->
|
||||||
|
case cpu_sup:util([detailed]) of
|
||||||
|
%% Not support for Windows
|
||||||
|
{_, 0, 0, _} -> 0;
|
||||||
|
{_Num, _Use, IdleList, _} -> proplists:get_value(idle, IdleList, 0)
|
||||||
|
end;
|
||||||
|
vm_stats('cpu.use') ->
|
||||||
|
100 - vm_stats('cpu.idle');
|
||||||
|
vm_stats('total.memory') ->
|
||||||
|
{_, MemTotal} = get_sys_memory(),
|
||||||
|
MemTotal;
|
||||||
|
vm_stats('used.memory') ->
|
||||||
|
{MemUsedRatio, MemTotal} = get_sys_memory(),
|
||||||
|
erlang:round(MemTotal * MemUsedRatio);
|
||||||
|
vm_stats('run.queue') ->
|
||||||
|
erlang:statistics(run_queue).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Brokers
|
%% Brokers
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
|
@ -269,7 +269,6 @@ create_trace(Name, ClientId, Start) ->
|
||||||
).
|
).
|
||||||
|
|
||||||
t_stream_log(_Config) ->
|
t_stream_log(_Config) ->
|
||||||
application:set_env(emqx, allow_anonymous, true),
|
|
||||||
emqx_trace:clear(),
|
emqx_trace:clear(),
|
||||||
load(),
|
load(),
|
||||||
ClientId = <<"client-stream">>,
|
ClientId = <<"client-stream">>,
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
emqx_opentelemetry
|
||||||
|
=====
|
||||||
|
|
||||||
|
OpenTelemetry metric log trace framework for EMQX.
|
|
@ -0,0 +1,29 @@
|
||||||
|
%% -*- mode: erlang -*-
|
||||||
|
|
||||||
|
{deps, [
|
||||||
|
{emqx, {path, "../emqx"}}
|
||||||
|
]}.
|
||||||
|
|
||||||
|
{edoc_opts, [{preprocess, true}]}.
|
||||||
|
{erl_opts, [
|
||||||
|
warn_unused_vars,
|
||||||
|
warn_shadow_vars,
|
||||||
|
warn_unused_import,
|
||||||
|
warn_obsolete_guard,
|
||||||
|
debug_info,
|
||||||
|
{parse_transform}
|
||||||
|
]}.
|
||||||
|
|
||||||
|
{xref_checks, [
|
||||||
|
undefined_function_calls,
|
||||||
|
undefined_functions,
|
||||||
|
locals_not_used,
|
||||||
|
deprecated_function_calls,
|
||||||
|
warnings_as_errors,
|
||||||
|
deprecated_functions
|
||||||
|
]}.
|
||||||
|
{cover_enabled, true}.
|
||||||
|
{cover_opts, [verbose]}.
|
||||||
|
{cover_export_enabled, true}.
|
||||||
|
|
||||||
|
{project_plugins, [erlfmt]}.
|
|
@ -0,0 +1,15 @@
|
||||||
|
{application, emqx_opentelemetry, [
|
||||||
|
{description, "OpenTelemetry for EMQX Broker"},
|
||||||
|
{vsn, "0.1.0"},
|
||||||
|
{registered, []},
|
||||||
|
{mod, {emqx_otel_app, []}},
|
||||||
|
{applications, [kernel, stdlib, emqx]},
|
||||||
|
{env, []},
|
||||||
|
{modules, []},
|
||||||
|
{licenses, ["Apache 2.0"]},
|
||||||
|
{maintainers, ["EMQX Team <contact@emqx.io>"]},
|
||||||
|
{links, [
|
||||||
|
{"Homepage", "https://emqx.io/"},
|
||||||
|
{"Github", "https://github.com/emqx/emqx"}
|
||||||
|
]}
|
||||||
|
]}.
|
|
@ -0,0 +1,207 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%
|
||||||
|
%% 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.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(emqx_otel).
|
||||||
|
-include_lib("emqx/include/logger.hrl").
|
||||||
|
|
||||||
|
-export([start_link/1]).
|
||||||
|
-export([get_cluster_gauge/1, get_stats_gauge/1, get_vm_gauge/1, get_metric_counter/1]).
|
||||||
|
-export([init/1, handle_continue/2, handle_call/3, handle_cast/2, handle_info/2, terminate/2]).
|
||||||
|
|
||||||
|
start_link(Conf) ->
|
||||||
|
gen_server:start_link({local, ?MODULE}, ?MODULE, Conf, []).
|
||||||
|
|
||||||
|
init(Conf) ->
|
||||||
|
erlang:process_flag(trap_exit, true),
|
||||||
|
{ok, #{}, {continue, {setup, Conf}}}.
|
||||||
|
|
||||||
|
handle_continue({setup, Conf}, State) ->
|
||||||
|
setup(Conf),
|
||||||
|
{noreply, State, hibernate}.
|
||||||
|
|
||||||
|
handle_call(_Msg, _From, State) ->
|
||||||
|
{reply, ok, State}.
|
||||||
|
|
||||||
|
handle_cast(_Msg, State) ->
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
handle_info(_Msg, State) ->
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
terminate(_Reason, _State) ->
|
||||||
|
cleanup(),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
setup(Conf = #{enable := true}) ->
|
||||||
|
ensure_apps(Conf),
|
||||||
|
create_metric_views();
|
||||||
|
setup(_Conf) ->
|
||||||
|
cleanup(),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
ensure_apps(Conf) ->
|
||||||
|
#{exporter := #{interval := ExporterInterval}} = Conf,
|
||||||
|
{ok, _} = application:ensure_all_started(opentelemetry_exporter),
|
||||||
|
_ = application:stop(opentelemetry_experimental),
|
||||||
|
ok = application:set_env(
|
||||||
|
opentelemetry_experimental,
|
||||||
|
readers,
|
||||||
|
[
|
||||||
|
#{
|
||||||
|
module => otel_metric_reader,
|
||||||
|
config => #{
|
||||||
|
exporter => {opentelemetry_exporter, #{}},
|
||||||
|
export_interval_ms => ExporterInterval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
),
|
||||||
|
{ok, _} = application:ensure_all_started(opentelemetry_experimental),
|
||||||
|
{ok, _} = application:ensure_all_started(opentelemetry_api_experimental),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
cleanup() ->
|
||||||
|
_ = application:stop(opentelemetry_experimental),
|
||||||
|
_ = application:stop(opentelemetry_experimental_api),
|
||||||
|
_ = application:stop(opentelemetry_exporter),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
create_metric_views() ->
|
||||||
|
Meter = opentelemetry_experimental:get_meter(),
|
||||||
|
StatsGauge = emqx_stats:getstats(),
|
||||||
|
create_gauge(Meter, StatsGauge, fun ?MODULE:get_stats_gauge/1),
|
||||||
|
VmGauge = lists:map(fun({K, V}) -> {normalize_name(K), V} end, emqx_mgmt:vm_stats()),
|
||||||
|
create_gauge(Meter, VmGauge, fun ?MODULE:get_vm_gauge/1),
|
||||||
|
ClusterGauge = [{'node.running', 0}, {'node.stopped', 0}],
|
||||||
|
create_gauge(Meter, ClusterGauge, fun ?MODULE:get_cluster_gauge/1),
|
||||||
|
Metrics = lists:map(fun({K, V}) -> {K, V, unit(K)} end, emqx_metrics:all()),
|
||||||
|
create_counter(Meter, Metrics, fun ?MODULE:get_metric_counter/1),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
unit(K) ->
|
||||||
|
case lists:member(K, bytes_metrics()) of
|
||||||
|
true -> kb;
|
||||||
|
false -> '1'
|
||||||
|
end.
|
||||||
|
|
||||||
|
bytes_metrics() ->
|
||||||
|
[
|
||||||
|
'bytes.received',
|
||||||
|
'bytes.sent',
|
||||||
|
'packets.received',
|
||||||
|
'packets.sent',
|
||||||
|
'packets.connect',
|
||||||
|
'packets.connack.sent',
|
||||||
|
'packets.connack.error',
|
||||||
|
'packets.connack.auth_error',
|
||||||
|
'packets.publish.received',
|
||||||
|
'packets.publish.sent',
|
||||||
|
'packets.publish.inuse',
|
||||||
|
'packets.publish.error',
|
||||||
|
'packets.publish.auth_error',
|
||||||
|
'packets.publish.dropped',
|
||||||
|
'packets.puback.received',
|
||||||
|
'packets.puback.sent',
|
||||||
|
'packets.puback.inuse',
|
||||||
|
'packets.puback.missed',
|
||||||
|
'packets.pubrec.received',
|
||||||
|
'packets.pubrec.sent',
|
||||||
|
'packets.pubrec.inuse',
|
||||||
|
'packets.pubrec.missed',
|
||||||
|
'packets.pubrel.received',
|
||||||
|
'packets.pubrel.sent',
|
||||||
|
'packets.pubrel.missed',
|
||||||
|
'packets.pubcomp.received',
|
||||||
|
'packets.pubcomp.sent',
|
||||||
|
'packets.pubcomp.inuse',
|
||||||
|
'packets.pubcomp.missed',
|
||||||
|
'packets.subscribe.received',
|
||||||
|
'packets.subscribe.error',
|
||||||
|
'packets.subscribe.auth_error',
|
||||||
|
'packets.suback.sent',
|
||||||
|
'packets.unsubscribe.received',
|
||||||
|
'packets.unsubscribe.error',
|
||||||
|
'packets.unsuback.sent',
|
||||||
|
'packets.pingreq.received',
|
||||||
|
'packets.pingresp.sent',
|
||||||
|
'packets.disconnect.received',
|
||||||
|
'packets.disconnect.sent',
|
||||||
|
'packets.auth.received',
|
||||||
|
'packets.auth.sent'
|
||||||
|
].
|
||||||
|
|
||||||
|
get_stats_gauge(Name) ->
|
||||||
|
[{emqx_stats:getstat(Name), #{}}].
|
||||||
|
|
||||||
|
get_vm_gauge(Name) ->
|
||||||
|
[{emqx_mgmt:vm_stats(Name), #{}}].
|
||||||
|
|
||||||
|
get_cluster_gauge('node.running') ->
|
||||||
|
length(emqx:cluster_nodes(running));
|
||||||
|
get_cluster_gauge('node.stopped') ->
|
||||||
|
length(emqx:cluster_nodes(stopped)).
|
||||||
|
|
||||||
|
get_metric_counter(Name) ->
|
||||||
|
[{emqx_metrics:val(Name), #{}}].
|
||||||
|
|
||||||
|
create_gauge(Meter, Names, CallBack) ->
|
||||||
|
lists:foreach(
|
||||||
|
fun({Name, _}) ->
|
||||||
|
true = otel_meter_server:add_view(
|
||||||
|
#{instrument_name => Name},
|
||||||
|
#{aggregation_module => otel_aggregation_last_value}
|
||||||
|
),
|
||||||
|
otel_meter:create_observable_gauge(
|
||||||
|
Meter,
|
||||||
|
Name,
|
||||||
|
CallBack,
|
||||||
|
Name,
|
||||||
|
#{
|
||||||
|
description => iolist_to_binary([
|
||||||
|
<<"observable ">>, atom_to_binary(Name), <<" gauge">>
|
||||||
|
]),
|
||||||
|
unit => '1'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end,
|
||||||
|
Names
|
||||||
|
).
|
||||||
|
|
||||||
|
create_counter(Meter, Counters, CallBack) ->
|
||||||
|
lists:foreach(
|
||||||
|
fun({Name, _, Unit}) ->
|
||||||
|
true = otel_meter_server:add_view(
|
||||||
|
#{instrument_name => Name},
|
||||||
|
#{aggregation_module => otel_aggregation_sum}
|
||||||
|
),
|
||||||
|
otel_meter:create_observable_counter(
|
||||||
|
Meter,
|
||||||
|
Name,
|
||||||
|
CallBack,
|
||||||
|
Name,
|
||||||
|
#{
|
||||||
|
description => iolist_to_binary([
|
||||||
|
<<"observable ">>, atom_to_binary(Name), <<" counter">>
|
||||||
|
]),
|
||||||
|
unit => Unit
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end,
|
||||||
|
Counters
|
||||||
|
).
|
||||||
|
|
||||||
|
normalize_name(Name) ->
|
||||||
|
list_to_existing_atom(lists:flatten(string:replace(atom_to_list(Name), "_", ".", all))).
|
|
@ -0,0 +1,112 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%
|
||||||
|
%% 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.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(emqx_otel_api).
|
||||||
|
|
||||||
|
-behaviour(minirest_api).
|
||||||
|
|
||||||
|
-include_lib("hocon/include/hoconsc.hrl").
|
||||||
|
-include_lib("emqx/include/http_api.hrl").
|
||||||
|
|
||||||
|
-import(hoconsc, [ref/2]).
|
||||||
|
|
||||||
|
-export([
|
||||||
|
api_spec/0,
|
||||||
|
paths/0,
|
||||||
|
schema/1
|
||||||
|
]).
|
||||||
|
|
||||||
|
-export([config/2]).
|
||||||
|
|
||||||
|
-define(TAGS, [<<"Monitor">>]).
|
||||||
|
|
||||||
|
api_spec() ->
|
||||||
|
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
|
||||||
|
|
||||||
|
paths() ->
|
||||||
|
[
|
||||||
|
"/opentelemetry"
|
||||||
|
].
|
||||||
|
|
||||||
|
schema("/opentelemetry") ->
|
||||||
|
#{
|
||||||
|
'operationId' => config,
|
||||||
|
get =>
|
||||||
|
#{
|
||||||
|
description => "Get opentelmetry configuration",
|
||||||
|
tags => ?TAGS,
|
||||||
|
responses =>
|
||||||
|
#{200 => otel_config_schema()}
|
||||||
|
},
|
||||||
|
put =>
|
||||||
|
#{
|
||||||
|
description => "Update opentelmetry configuration",
|
||||||
|
tags => ?TAGS,
|
||||||
|
'requestBody' => otel_config_schema(),
|
||||||
|
responses =>
|
||||||
|
#{
|
||||||
|
200 => otel_config_schema(),
|
||||||
|
400 =>
|
||||||
|
emqx_dashboard_swagger:error_codes(
|
||||||
|
[?BAD_REQUEST], <<"Update Config Failed">>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% API Handler funcs
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
config(get, _Params) ->
|
||||||
|
{200, get_raw()};
|
||||||
|
config(put, #{body := Body}) ->
|
||||||
|
case emqx_otel_config:update(Body) of
|
||||||
|
{ok, NewConfig} ->
|
||||||
|
{200, NewConfig};
|
||||||
|
{error, Reason} ->
|
||||||
|
Message = list_to_binary(io_lib:format("Update config failed ~p", [Reason])),
|
||||||
|
{400, ?BAD_REQUEST, Message}
|
||||||
|
end.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Internal funcs
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
get_raw() ->
|
||||||
|
Path = <<"opentelemetry">>,
|
||||||
|
#{Path := Conf} =
|
||||||
|
emqx_config:fill_defaults(
|
||||||
|
#{Path => emqx_conf:get_raw([Path])},
|
||||||
|
#{obfuscate_sensitive_values => true}
|
||||||
|
),
|
||||||
|
Conf.
|
||||||
|
|
||||||
|
otel_config_schema() ->
|
||||||
|
emqx_dashboard_swagger:schema_with_example(
|
||||||
|
ref(emqx_otel_schema, "opentelemetry"),
|
||||||
|
otel_config_example()
|
||||||
|
).
|
||||||
|
|
||||||
|
otel_config_example() ->
|
||||||
|
#{
|
||||||
|
enable => true,
|
||||||
|
exporter =>
|
||||||
|
#{
|
||||||
|
endpoint => "http://localhost:4317",
|
||||||
|
interval => "10s"
|
||||||
|
}
|
||||||
|
}.
|
|
@ -0,0 +1,29 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%
|
||||||
|
%% 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.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(emqx_otel_app).
|
||||||
|
|
||||||
|
-behaviour(application).
|
||||||
|
|
||||||
|
-export([start/2, stop/1]).
|
||||||
|
|
||||||
|
start(_StartType, _StartArgs) ->
|
||||||
|
emqx_otel_config:add_handler(),
|
||||||
|
emqx_otel_sup:start_link().
|
||||||
|
|
||||||
|
stop(_State) ->
|
||||||
|
emqx_otel_config:remove_handler(),
|
||||||
|
ok.
|
|
@ -0,0 +1,58 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%
|
||||||
|
%% 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.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-module(emqx_otel_config).
|
||||||
|
|
||||||
|
-behaviour(emqx_config_handler).
|
||||||
|
|
||||||
|
-define(OPTL, [opentelemetry]).
|
||||||
|
|
||||||
|
-export([add_handler/0, remove_handler/0]).
|
||||||
|
-export([post_config_update/5]).
|
||||||
|
-export([update/1]).
|
||||||
|
|
||||||
|
update(Config) ->
|
||||||
|
case
|
||||||
|
emqx_conf:update(
|
||||||
|
?OPTL,
|
||||||
|
Config,
|
||||||
|
#{rawconf_with_defaults => true, override_to => cluster}
|
||||||
|
)
|
||||||
|
of
|
||||||
|
{ok, #{raw_config := NewConfigRows}} ->
|
||||||
|
{ok, NewConfigRows};
|
||||||
|
{error, Reason} ->
|
||||||
|
{error, Reason}
|
||||||
|
end.
|
||||||
|
|
||||||
|
add_handler() ->
|
||||||
|
ok = emqx_config_handler:add_handler(?OPTL, ?MODULE),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
remove_handler() ->
|
||||||
|
ok = emqx_config_handler:remove_handler(?OPTL),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
post_config_update(?OPTL, _Req, New, _Old, AppEnvs) ->
|
||||||
|
application:set_env(AppEnvs),
|
||||||
|
ensure_otel(New);
|
||||||
|
post_config_update(_ConfPath, _Req, _NewConf, _OldConf, _AppEnvs) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
ensure_otel(#{enable := true} = Conf) ->
|
||||||
|
_ = emqx_otel_sup:stop_otel(),
|
||||||
|
emqx_otel_sup:start_otel(Conf);
|
||||||
|
ensure_otel(#{enable := false}) ->
|
||||||
|
emqx_otel_sup:stop_otel().
|
|
@ -0,0 +1,82 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%
|
||||||
|
%% 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.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-module(emqx_otel_schema).
|
||||||
|
|
||||||
|
-include_lib("hocon/include/hoconsc.hrl").
|
||||||
|
|
||||||
|
-export([
|
||||||
|
roots/0,
|
||||||
|
fields/1,
|
||||||
|
namespace/0,
|
||||||
|
desc/1
|
||||||
|
]).
|
||||||
|
|
||||||
|
namespace() -> opentelemetry.
|
||||||
|
roots() -> ["opentelemetry"].
|
||||||
|
|
||||||
|
fields("opentelemetry") ->
|
||||||
|
[
|
||||||
|
{exporter,
|
||||||
|
?HOCON(
|
||||||
|
?R_REF("exporter"),
|
||||||
|
#{desc => ?DESC(exporter)}
|
||||||
|
)},
|
||||||
|
{enable,
|
||||||
|
?HOCON(
|
||||||
|
boolean(),
|
||||||
|
#{
|
||||||
|
default => false,
|
||||||
|
required => true,
|
||||||
|
desc => ?DESC(enable)
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
];
|
||||||
|
fields("exporter") ->
|
||||||
|
[
|
||||||
|
{"protocol",
|
||||||
|
?HOCON(
|
||||||
|
%% http_protobuf is not support for metrics yet.
|
||||||
|
?ENUM([grpc]),
|
||||||
|
#{
|
||||||
|
mapping => "opentelemetry_exporter.otlp_protocol",
|
||||||
|
desc => ?DESC(protocol),
|
||||||
|
default => grpc,
|
||||||
|
importance => ?IMPORTANCE_HIDDEN
|
||||||
|
}
|
||||||
|
)},
|
||||||
|
{"endpoint",
|
||||||
|
?HOCON(
|
||||||
|
emqx_schema:url(),
|
||||||
|
#{
|
||||||
|
mapping => "opentelemetry_exporter.otlp_endpoint",
|
||||||
|
default => "http://localhost:4317",
|
||||||
|
desc => ?DESC(endpoint)
|
||||||
|
}
|
||||||
|
)},
|
||||||
|
{"interval",
|
||||||
|
?HOCON(
|
||||||
|
emqx_schema:timeout_duration_ms(),
|
||||||
|
#{
|
||||||
|
default => <<"10s">>,
|
||||||
|
required => true,
|
||||||
|
desc => ?DESC(interval)
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
].
|
||||||
|
|
||||||
|
desc("opentelemetry") -> ?DESC(opentelemetry);
|
||||||
|
desc("exporter") -> ?DESC(exporter);
|
||||||
|
desc(_) -> undefined.
|
|
@ -0,0 +1,67 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%
|
||||||
|
%% 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.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-module(emqx_otel_sup).
|
||||||
|
|
||||||
|
-behaviour(supervisor).
|
||||||
|
|
||||||
|
-export([start_link/0]).
|
||||||
|
-export([init/1]).
|
||||||
|
-export([start_otel/1]).
|
||||||
|
-export([stop_otel/0]).
|
||||||
|
|
||||||
|
-define(CHILD(Mod, Opts), #{
|
||||||
|
id => Mod,
|
||||||
|
start => {Mod, start_link, [Opts]},
|
||||||
|
restart => permanent,
|
||||||
|
shutdown => 5000,
|
||||||
|
type => worker,
|
||||||
|
modules => [Mod]
|
||||||
|
}).
|
||||||
|
|
||||||
|
-define(WORKER, emqx_otel).
|
||||||
|
|
||||||
|
start_link() ->
|
||||||
|
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||||
|
|
||||||
|
-spec start_otel(map()) -> ok.
|
||||||
|
start_otel(Conf) ->
|
||||||
|
assert_started(supervisor:start_child(?MODULE, ?CHILD(?WORKER, Conf))).
|
||||||
|
|
||||||
|
-spec stop_otel() -> ok | {error, term()}.
|
||||||
|
stop_otel() ->
|
||||||
|
case supervisor:terminate_child(?MODULE, ?WORKER) of
|
||||||
|
ok -> supervisor:delete_child(?MODULE, ?WORKER);
|
||||||
|
{error, not_found} -> ok;
|
||||||
|
Error -> Error
|
||||||
|
end.
|
||||||
|
|
||||||
|
init([]) ->
|
||||||
|
SupFlags = #{
|
||||||
|
strategy => one_for_one,
|
||||||
|
intensity => 10,
|
||||||
|
period => 512
|
||||||
|
},
|
||||||
|
Children =
|
||||||
|
case emqx_conf:get([opentelemetry]) of
|
||||||
|
#{enable := false} -> [];
|
||||||
|
#{enable := true} = Conf -> [?CHILD(?WORKER, Conf)]
|
||||||
|
end,
|
||||||
|
{ok, {SupFlags, Children}}.
|
||||||
|
|
||||||
|
assert_started({ok, _Pid}) -> ok;
|
||||||
|
assert_started({ok, _Pid, _Info}) -> ok;
|
||||||
|
assert_started({error, {already_started, _Pid}}) -> ok;
|
||||||
|
assert_started({error, Reason}) -> {error, Reason}.
|
|
@ -2,7 +2,7 @@
|
||||||
{application, emqx_prometheus, [
|
{application, emqx_prometheus, [
|
||||||
{description, "Prometheus for EMQX"},
|
{description, "Prometheus for EMQX"},
|
||||||
% strict semver, bump manually!
|
% strict semver, bump manually!
|
||||||
{vsn, "5.0.14"},
|
{vsn, "5.0.15"},
|
||||||
{modules, []},
|
{modules, []},
|
||||||
{registered, [emqx_prometheus_sup]},
|
{registered, [emqx_prometheus_sup]},
|
||||||
{applications, [kernel, stdlib, prometheus, emqx, emqx_management]},
|
{applications, [kernel, stdlib, prometheus, emqx, emqx_management]},
|
||||||
|
|
|
@ -160,7 +160,7 @@ collect_mf(_Registry, Callback) ->
|
||||||
Stats = emqx_stats:getstats(),
|
Stats = emqx_stats:getstats(),
|
||||||
VMData = emqx_vm_data(),
|
VMData = emqx_vm_data(),
|
||||||
ClusterData = emqx_cluster_data(),
|
ClusterData = emqx_cluster_data(),
|
||||||
_ = [add_collect_family(Name, Stats, Callback, gauge) || Name <- emqx_stats()],
|
_ = [add_collect_family(Name, Stats, Callback, gauge) || Name <- emqx_stats:names()],
|
||||||
_ = [add_collect_family(Name, VMData, Callback, gauge) || Name <- emqx_vm()],
|
_ = [add_collect_family(Name, VMData, Callback, gauge) || Name <- emqx_vm()],
|
||||||
_ = [add_collect_family(Name, ClusterData, Callback, gauge) || Name <- emqx_cluster()],
|
_ = [add_collect_family(Name, ClusterData, Callback, gauge) || Name <- emqx_cluster()],
|
||||||
_ = [add_collect_family(Name, Metrics, Callback, counter) || Name <- emqx_metrics_packets()],
|
_ = [add_collect_family(Name, Metrics, Callback, counter) || Name <- emqx_metrics_packets()],
|
||||||
|
@ -176,7 +176,7 @@ collect(<<"json">>) ->
|
||||||
Stats = emqx_stats:getstats(),
|
Stats = emqx_stats:getstats(),
|
||||||
VMData = emqx_vm_data(),
|
VMData = emqx_vm_data(),
|
||||||
#{
|
#{
|
||||||
stats => maps:from_list([collect_stats(Name, Stats) || Name <- emqx_stats()]),
|
stats => maps:from_list([collect_stats(Name, Stats) || Name <- emqx_stats:names()]),
|
||||||
metrics => maps:from_list([collect_stats(Name, VMData) || Name <- emqx_vm()]),
|
metrics => maps:from_list([collect_stats(Name, VMData) || Name <- emqx_vm()]),
|
||||||
packets => maps:from_list([collect_stats(Name, Metrics) || Name <- emqx_metrics_packets()]),
|
packets => maps:from_list([collect_stats(Name, Metrics) || Name <- emqx_metrics_packets()]),
|
||||||
messages => maps:from_list([collect_stats(Name, Metrics) || Name <- emqx_metrics_messages()]),
|
messages => maps:from_list([collect_stats(Name, Metrics) || Name <- emqx_metrics_messages()]),
|
||||||
|
@ -460,28 +460,6 @@ emqx_collect(emqx_cluster_nodes_stopped, ClusterData) ->
|
||||||
%% Indicators
|
%% Indicators
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
emqx_stats() ->
|
|
||||||
[
|
|
||||||
emqx_connections_count,
|
|
||||||
emqx_connections_max,
|
|
||||||
emqx_live_connections_count,
|
|
||||||
emqx_live_connections_max,
|
|
||||||
emqx_sessions_count,
|
|
||||||
emqx_sessions_max,
|
|
||||||
emqx_topics_count,
|
|
||||||
emqx_topics_max,
|
|
||||||
emqx_suboptions_count,
|
|
||||||
emqx_suboptions_max,
|
|
||||||
emqx_subscribers_count,
|
|
||||||
emqx_subscribers_max,
|
|
||||||
emqx_subscriptions_count,
|
|
||||||
emqx_subscriptions_max,
|
|
||||||
emqx_subscriptions_shared_count,
|
|
||||||
emqx_subscriptions_shared_max,
|
|
||||||
emqx_retained_count,
|
|
||||||
emqx_retained_max
|
|
||||||
].
|
|
||||||
|
|
||||||
emqx_metrics_packets() ->
|
emqx_metrics_packets() ->
|
||||||
[
|
[
|
||||||
emqx_bytes_received,
|
emqx_bytes_received,
|
||||||
|
|
|
@ -48,9 +48,13 @@
|
||||||
|
|
||||||
-define(PH_VAR_THIS, '$this').
|
-define(PH_VAR_THIS, '$this').
|
||||||
|
|
||||||
-define(EX_PLACE_HOLDER, "(\\$\\{[a-zA-Z0-9\\._]+\\})").
|
%% To match any pattern starts with '$' and followed by '{', and closed by a '}' char:
|
||||||
|
%% e.g. for string "a${abc}bb", "${abc}" will be matched.
|
||||||
|
%% Note this is non-greedy matching
|
||||||
|
%% e.g. if "${{abc}}" is given, the "${{abc}" should be matched, NOT "${{abc}}".
|
||||||
|
-define(EX_PLACE_HOLDER, "(\\$\\{[^}]+\\})").
|
||||||
|
|
||||||
-define(EX_PLACE_HOLDER_DOUBLE_QUOTE, "(\\$\\{[a-zA-Z0-9\\._]+\\}|\"\\$\\{[a-zA-Z0-9\\._]+\\}\")").
|
-define(EX_PLACE_HOLDER_DOUBLE_QUOTE, "(\\$\\{[^}]+\\}|\"\\$\\{[^}]+\\}\")").
|
||||||
|
|
||||||
%% Space and CRLF
|
%% Space and CRLF
|
||||||
-define(EX_WITHE_CHARS, "\\s").
|
-define(EX_WITHE_CHARS, "\\s").
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{application, emqx_utils, [
|
{application, emqx_utils, [
|
||||||
{description, "Miscellaneous utilities for EMQX apps"},
|
{description, "Miscellaneous utilities for EMQX apps"},
|
||||||
% strict semver, bump manually!
|
% strict semver, bump manually!
|
||||||
{vsn, "5.0.5"},
|
{vsn, "5.0.6"},
|
||||||
{modules, [
|
{modules, [
|
||||||
emqx_utils,
|
emqx_utils,
|
||||||
emqx_utils_api,
|
emqx_utils_api,
|
||||||
|
|
|
@ -206,3 +206,53 @@ t_preproc_tmpl_deep(_) ->
|
||||||
#{<<"${a}">> => [<<"1">>, "c", 2, 3.0, '${d}', {[<<"1.0">>], 0}]},
|
#{<<"${a}">> => [<<"1">>, "c", 2, 3.0, '${d}', {[<<"1.0">>], 0}]},
|
||||||
emqx_placeholder:proc_tmpl_deep(Tmpl1, Selected)
|
emqx_placeholder:proc_tmpl_deep(Tmpl1, Selected)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
t_proc_tmpl_arbitrary_var_name(_) ->
|
||||||
|
Selected = #{
|
||||||
|
<<"中"/utf8>> => <<"1">>,
|
||||||
|
<<"中-1"/utf8>> => <<"1-1">>,
|
||||||
|
<<"-_+=<>,/?:;\"'\\[]|">> => 1,
|
||||||
|
<<"-_+=<>,">> => #{<<"/?:;\"'\\[]|">> => 2},
|
||||||
|
<<"!@#$%^&*()">> => 1.0,
|
||||||
|
<<"d">> => #{
|
||||||
|
<<"$ff">> => <<"oo">>,
|
||||||
|
<<"${f">> => <<"hi">>,
|
||||||
|
<<"${f}">> => <<"qq">>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Tks = emqx_placeholder:preproc_tmpl(
|
||||||
|
<<
|
||||||
|
"a:${中},a:${中-1},b:${-_+=<>,/?:;\"'\\[]|},"
|
||||||
|
"b:${-_+=<>,./?:;\"'\\[]|},c:${!@#$%^&*()},d:${d.$ff},d1:${d.${f}}"/utf8
|
||||||
|
>>
|
||||||
|
),
|
||||||
|
?assertEqual(
|
||||||
|
<<"a:1,a:1-1,b:1,b:2,c:1.0,d:oo,d1:hi}">>,
|
||||||
|
emqx_placeholder:proc_tmpl(Tks, Selected)
|
||||||
|
).
|
||||||
|
|
||||||
|
t_proc_tmpl_arbitrary_var_name_double_quote(_) ->
|
||||||
|
Selected = #{
|
||||||
|
<<"中"/utf8>> => <<"1">>,
|
||||||
|
<<"中-1"/utf8>> => <<"1-1">>,
|
||||||
|
<<"-_+=<>,/?:;\"'\\[]|">> => 1,
|
||||||
|
<<"-_+=<>,">> => #{<<"/?:;\"'\\[]|">> => 2},
|
||||||
|
<<"!@#$%^&*()">> => 1.0,
|
||||||
|
<<"d">> => #{
|
||||||
|
<<"$ff">> => <<"oo">>,
|
||||||
|
<<"${f">> => <<"hi">>,
|
||||||
|
<<"${f}">> => <<"qq">>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Tks = emqx_placeholder:preproc_tmpl(
|
||||||
|
<<
|
||||||
|
"a:\"${中}\",a:\"${中-1}\",b:\"${-_+=<>,/?:;\"'\\[]|}\","
|
||||||
|
"b:\"${-_+=<>,./?:;\"'\\[]|}\",c:\"${!@#$%^&*()}\",d:\"${d.$ff}\",d1:\"${d.${f}\"}"/utf8
|
||||||
|
>>,
|
||||||
|
#{strip_double_quote => true}
|
||||||
|
),
|
||||||
|
ct:print("TKs:~p~n", [Tks]),
|
||||||
|
?assertEqual(
|
||||||
|
<<"a:1,a:1-1,b:1,b:2,c:1.0,d:oo,d1:hi}">>,
|
||||||
|
emqx_placeholder:proc_tmpl(Tks, Selected)
|
||||||
|
).
|
||||||
|
|
12
build
12
build
|
@ -378,11 +378,11 @@ make_docker() {
|
||||||
local EMQX_DOCKERFILE="${EMQX_DOCKERFILE:-deploy/docker/Dockerfile}"
|
local EMQX_DOCKERFILE="${EMQX_DOCKERFILE:-deploy/docker/Dockerfile}"
|
||||||
local PKG_VSN="${PKG_VSN:-$(./pkg-vsn.sh)}"
|
local PKG_VSN="${PKG_VSN:-$(./pkg-vsn.sh)}"
|
||||||
# shellcheck disable=SC2155
|
# shellcheck disable=SC2155
|
||||||
local VSN_MAJOR="$(echo "$PKG_VSN" | cut -d . -f 1)"
|
local VSN_MAJOR="$(scripts/semver.sh "$PKG_VSN" --major)"
|
||||||
# shellcheck disable=SC2155
|
# shellcheck disable=SC2155
|
||||||
local VSN_MINOR="$(echo "$PKG_VSN" | cut -d . -f 2)"
|
local VSN_MINOR="$(scripts/semver.sh "$PKG_VSN" --minor)"
|
||||||
# shellcheck disable=SC2155
|
# shellcheck disable=SC2155
|
||||||
local VSN_PATCH="$(echo "$PKG_VSN" | cut -d . -f 3)"
|
local VSN_MINOR="$(scripts/semver.sh "$PKG_VSN" --patch)"
|
||||||
local SUFFIX=''
|
local SUFFIX=''
|
||||||
if [[ "$PROFILE" = *-elixir ]]; then
|
if [[ "$PROFILE" = *-elixir ]]; then
|
||||||
SUFFIX="-elixir"
|
SUFFIX="-elixir"
|
||||||
|
@ -430,8 +430,6 @@ make_docker() {
|
||||||
--label org.opencontainers.image.licenses="${LICENSE}" \
|
--label org.opencontainers.image.licenses="${LICENSE}" \
|
||||||
--label org.opencontainers.image.otp.version="${EMQX_BUILDER_OTP}" \
|
--label org.opencontainers.image.otp.version="${EMQX_BUILDER_OTP}" \
|
||||||
--tag "${EMQX_IMAGE_TAG}" \
|
--tag "${EMQX_IMAGE_TAG}" \
|
||||||
--tag "${EMQX_BASE_DOCKER_TAG}:${VSN_MAJOR}.${VSN_MINOR}${SUFFIX}" \
|
|
||||||
--tag "${EMQX_BASE_DOCKER_TAG}:${VSN_MAJOR}.${VSN_MINOR}.${VSN_PATCH}${SUFFIX}" \
|
|
||||||
--provenance false \
|
--provenance false \
|
||||||
--pull
|
--pull
|
||||||
)
|
)
|
||||||
|
@ -442,7 +440,9 @@ make_docker() {
|
||||||
DOCKER_BUILDX_ARGS+=(--label org.opencontainers.image.elixir.version="${EMQX_BUILDER_ELIXIR}")
|
DOCKER_BUILDX_ARGS+=(--label org.opencontainers.image.elixir.version="${EMQX_BUILDER_ELIXIR}")
|
||||||
fi
|
fi
|
||||||
if [ "${DOCKER_LATEST:-false}" = true ]; then
|
if [ "${DOCKER_LATEST:-false}" = true ]; then
|
||||||
DOCKER_BUILDX_ARGS+=(--tag "${DOCKER_REGISTRY}/${DOCKER_ORG}/${PROFILE}:latest${SUFFIX}")
|
DOCKER_BUILDX_ARGS+=(--tag "${EMQX_BASE_DOCKER_TAG}:latest${SUFFIX}")
|
||||||
|
DOCKER_BUILDX_ARGS+=(--tag "${EMQX_BASE_DOCKER_TAG}:${VSN_MAJOR}.${VSN_MINOR}${SUFFIX}")
|
||||||
|
DOCKER_BUILDX_ARGS+=(--tag "${EMQX_BASE_DOCKER_TAG}:${VSN_MAJOR}.${VSN_MINOR}.${VSN_PATCH}${SUFFIX}")
|
||||||
fi
|
fi
|
||||||
if [ "${DOCKER_PLATFORMS:-default}" != 'default' ]; then
|
if [ "${DOCKER_PLATFORMS:-default}" != 'default' ]; then
|
||||||
DOCKER_BUILDX_ARGS+=(--platform "${DOCKER_PLATFORMS}")
|
DOCKER_BUILDX_ARGS+=(--platform "${DOCKER_PLATFORMS}")
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Prevent client disconnected when sending large payloads with debug/trace logging is enabled.
|
|
@ -0,0 +1,8 @@
|
||||||
|
Improved the placeholder syntax of rule engine.
|
||||||
|
|
||||||
|
The parameters of actions support using placeholder syntax to
|
||||||
|
dynamically fill in the content of strings. The format of the
|
||||||
|
placeholder syntax is `${key}`.
|
||||||
|
Before this improvement, the `key` in `${key}` could only contain
|
||||||
|
letters, numbers, and underscores. Now the `key` supports any UTF8
|
||||||
|
characters.
|
28
mix.exs
28
mix.exs
|
@ -98,7 +98,32 @@ defmodule EMQXUmbrella.MixProject do
|
||||||
# set by hackney (dependency)
|
# set by hackney (dependency)
|
||||||
{:ssl_verify_fun, "1.1.6", override: true},
|
{:ssl_verify_fun, "1.1.6", override: true},
|
||||||
{:uuid, github: "okeuday/uuid", tag: "v2.0.6", override: true},
|
{:uuid, github: "okeuday/uuid", tag: "v2.0.6", override: true},
|
||||||
{:quickrand, github: "okeuday/quickrand", tag: "v2.0.6", override: true}
|
{:quickrand, github: "okeuday/quickrand", tag: "v2.0.6", override: true},
|
||||||
|
{:opentelemetry_api,
|
||||||
|
github: "emqx/opentelemetry-erlang",
|
||||||
|
sparse: "apps/opentelemetry_api",
|
||||||
|
override: true,
|
||||||
|
runtime: false},
|
||||||
|
{:opentelemetry,
|
||||||
|
github: "emqx/opentelemetry-erlang",
|
||||||
|
sparse: "apps/opentelemetry",
|
||||||
|
override: true,
|
||||||
|
runtime: false},
|
||||||
|
{:opentelemetry_api_experimental,
|
||||||
|
github: "emqx/opentelemetry-erlang",
|
||||||
|
sparse: "apps/opentelemetry_api_experimental",
|
||||||
|
override: true,
|
||||||
|
runtime: false},
|
||||||
|
{:opentelemetry_experimental,
|
||||||
|
github: "emqx/opentelemetry-erlang",
|
||||||
|
sparse: "apps/opentelemetry_experimental",
|
||||||
|
override: true,
|
||||||
|
runtime: false},
|
||||||
|
{:opentelemetry_exporter,
|
||||||
|
github: "emqx/opentelemetry-erlang",
|
||||||
|
sparse: "apps/opentelemetry_exporter",
|
||||||
|
override: true,
|
||||||
|
runtime: false}
|
||||||
] ++
|
] ++
|
||||||
emqx_apps(profile_info, version) ++
|
emqx_apps(profile_info, version) ++
|
||||||
enterprise_deps(profile_info) ++ bcrypt_dep() ++ jq_dep() ++ quicer_dep()
|
enterprise_deps(profile_info) ++ bcrypt_dep() ++ jq_dep() ++ quicer_dep()
|
||||||
|
@ -324,6 +349,7 @@ defmodule EMQXUmbrella.MixProject do
|
||||||
:emqx_plugins,
|
:emqx_plugins,
|
||||||
:emqx_ft,
|
:emqx_ft,
|
||||||
:emqx_s3,
|
:emqx_s3,
|
||||||
|
:emqx_opentelemetry,
|
||||||
:emqx_durable_storage,
|
:emqx_durable_storage,
|
||||||
:rabbit_common
|
:rabbit_common
|
||||||
],
|
],
|
||||||
|
|
|
@ -84,6 +84,14 @@
|
||||||
%% in conflict by erlavro and rocketmq
|
%% in conflict by erlavro and rocketmq
|
||||||
, {jsone, {git, "https://github.com/emqx/jsone.git", {tag, "1.7.1"}}}
|
, {jsone, {git, "https://github.com/emqx/jsone.git", {tag, "1.7.1"}}}
|
||||||
, {uuid, {git, "https://github.com/okeuday/uuid.git", {tag, "v2.0.6"}}}
|
, {uuid, {git, "https://github.com/okeuday/uuid.git", {tag, "v2.0.6"}}}
|
||||||
|
%% trace
|
||||||
|
, {opentelemetry_api, {git_subdir, "http://github.com/emqx/opentelemetry-erlang", {branch, "main"}, "apps/opentelemetry_api"}}
|
||||||
|
, {opentelemetry, {git_subdir, "http://github.com/emqx/opentelemetry-erlang", {branch, "main"}, "apps/opentelemetry"}}
|
||||||
|
%% log metrics
|
||||||
|
, {opentelemetry_experimental, {git_subdir, "http://github.com/emqx/opentelemetry-erlang", {branch, "main"}, "apps/opentelemetry_experimental"}}
|
||||||
|
, {opentelemetry_api_experimental, {git_subdir, "http://github.com/emqx/opentelemetry-erlang", {branch, "main"}, "apps/opentelemetry_api_experimental"}}
|
||||||
|
%% export
|
||||||
|
, {opentelemetry_exporter, {git_subdir, "http://github.com/emqx/opentelemetry-erlang", {branch, "main"}, "apps/opentelemetry_exporter"}}
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
{xref_ignores,
|
{xref_ignores,
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
emqx_otel_schema {
|
||||||
|
|
||||||
|
opentelemetry.desc: "Open Telemetry Toolkit configuration"
|
||||||
|
|
||||||
|
exporter.desc: "Open Telemetry Exporter"
|
||||||
|
|
||||||
|
enable.desc: "Enable or disable open telemetry metrics"
|
||||||
|
|
||||||
|
protocol.desc: "Open Telemetry Exporter Protocol"
|
||||||
|
|
||||||
|
endpoint.desc: "Open Telemetry Exporter Endpoint"
|
||||||
|
|
||||||
|
interval.desc: "The interval of sending metrics to Open Telemetry Endpoint"
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
function parseSemver() {
|
||||||
|
local RE='^([0-9]+)\.([0-9]+)\.([0-9]+)(-([a-z]+\.[0-9]+))?$'
|
||||||
|
echo "$1" | grep -qE "$RE" || exit 1
|
||||||
|
#shellcheck disable=SC2155
|
||||||
|
local MAJOR=$( echo "$1" | sed -r "s#$RE#\1#")
|
||||||
|
#shellcheck disable=SC2155
|
||||||
|
local MINOR=$( echo "$1" | sed -r "s#$RE#\2#")
|
||||||
|
#shellcheck disable=SC2155
|
||||||
|
local PATCH=$( echo "$1" | sed -r "s#$RE#\3#")
|
||||||
|
#shellcheck disable=SC2155
|
||||||
|
local SPECIAL=$(echo "$1" | sed -r "s#$RE#\5#")
|
||||||
|
case "${2}" in
|
||||||
|
--major) echo "${MAJOR}" ;;
|
||||||
|
--minor) echo "${MINOR}" ;;
|
||||||
|
--patch) echo "${PATCH}" ;;
|
||||||
|
--special) echo "${SPECIAL}" ;;
|
||||||
|
*)
|
||||||
|
cat <<EOF
|
||||||
|
{"major": ${MAJOR}, "minor": ${MINOR}, "patch": ${PATCH}, "special": "${SPECIAL}"}
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
parseSemver "$1" "$2"
|
|
@ -7,13 +7,13 @@ exit_code=0
|
||||||
|
|
||||||
for test in shelltest/*.test; do
|
for test in shelltest/*.test; do
|
||||||
echo "Running $test"
|
echo "Running $test"
|
||||||
/bin/sh "${test%.test}.setup"
|
[ -f "${test%.test}.setup" ] && /bin/sh "${test%.test}.setup"
|
||||||
shelltest -c --diff --all --precise -- "$test"
|
shelltest -c --diff --all --precise -- "$test"
|
||||||
# shellcheck disable=SC2181
|
# shellcheck disable=SC2181
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
exit_code=1
|
exit_code=1
|
||||||
fi
|
fi
|
||||||
/bin/sh "${test%.test}.cleanup"
|
[ -f "${test%.test}.cleanup" ] && /bin/sh "${test%.test}.cleanup"
|
||||||
done
|
done
|
||||||
|
|
||||||
exit $exit_code
|
exit $exit_code
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
./semver.sh 5.2.0.1
|
||||||
|
>>>= 1
|
||||||
|
|
||||||
|
./semver.sh 5.1.0
|
||||||
|
>>>
|
||||||
|
{"major": 5, "minor": 1, "patch": 0, "special": ""}
|
||||||
|
>>>= 0
|
||||||
|
|
||||||
|
./semver.sh 5.1.0-patch.3
|
||||||
|
>>>
|
||||||
|
{"major": 5, "minor": 1, "patch": 0, "special": "patch.3"}
|
||||||
|
>>>= 0
|
||||||
|
|
||||||
|
./semver.sh 5.1.0-patch.3 --major
|
||||||
|
>>>
|
||||||
|
5
|
||||||
|
>>>= 0
|
||||||
|
|
||||||
|
./semver.sh 5.1.0-patch.3 --minor
|
||||||
|
>>>
|
||||||
|
1
|
||||||
|
>>>= 0
|
||||||
|
|
||||||
|
./semver.sh 5.1.0-patch.3 --patch
|
||||||
|
>>>
|
||||||
|
0
|
||||||
|
>>>= 0
|
||||||
|
|
||||||
|
./semver.sh 5.1.0-patch.3 --special
|
||||||
|
>>>
|
||||||
|
patch.3
|
||||||
|
>>>= 0
|
Loading…
Reference in New Issue