From 2e195a44ecff6768ce9fe8a32a794a955235be70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20G=C3=B6m=C3=B6ri?= Date: Sun, 18 Jan 2026 23:24:53 +0100 Subject: [PATCH 1/5] remove `sync` app --- rebar.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rebar.config b/rebar.config index 95d2adfe..52b4c5b5 100644 --- a/rebar.config +++ b/rebar.config @@ -7,7 +7,7 @@ {cover_excl_mods, [test_module]}. -{shell, [{apps, [sync, xprof]}]}. +{shell, [{apps, [xprof]}]}. {profiles, [{test, @@ -25,7 +25,7 @@ [{deps, [ {thoas, "0.4.0"} ]} ]}, {dev, - [{deps, [ {sync, "0.1.3"} ]} + [ %% {deps, [ {sync, "0.1.3"} ]} ]}, {publish, [{plugins, [ {rebar3_hex, {git, "https://github.com/gomoripeti/rebar3_hex.git", {tag, "deps-3"}}} ]} From cddaf0e5365af960d288c31f54113692d52a7c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20G=C3=B6m=C3=B6ri?= Date: Sun, 13 Oct 2019 22:47:54 -0500 Subject: [PATCH 2/5] Update docs - use rebar3_ex_doc plugin to generate documentation - publish to hexdocs --- .github/workflows/ci.yml | 37 +++++++++++++++-- Makefile | 19 +++++---- apps/xprof/src/xprof.app.src | 1 + apps/xprof_core/src/test_module.erl | 1 + apps/xprof_core/src/xprof_core.erl | 40 ++++++++++++++----- apps/xprof_core/src/xprof_core_app.erl | 1 + apps/xprof_core/src/xprof_core_cmd.erl | 3 +- .../xprof_core/src/xprof_core_cmd_argdist.erl | 1 + .../src/xprof_core_cmd_funlatency.erl | 1 + .../src/xprof_core_elixir_syntax.erl | 3 +- .../src/xprof_core_erlang_syntax.erl | 1 + apps/xprof_core/src/xprof_core_hist.erl | 1 + apps/xprof_core/src/xprof_core_language.erl | 3 +- apps/xprof_core/src/xprof_core_lib.erl | 1 + apps/xprof_core/src/xprof_core_ms.erl | 1 + apps/xprof_core/src/xprof_core_query.erl | 1 + apps/xprof_core/src/xprof_core_records.erl | 1 + apps/xprof_core/src/xprof_core_sup.erl | 1 + .../src/xprof_core_trace_handler.erl | 1 + .../src/xprof_core_trace_handler_sup.erl | 1 + apps/xprof_core/src/xprof_core_tracer.erl | 1 + apps/xprof_core/src/xprof_core_vm_info.erl | 1 + doc/docs.exs | 13 ------ doc/src/commands.md | 8 ++-- doc/src/querysyntax.md | 5 ++- rebar.config | 20 +++++++++- 26 files changed, 122 insertions(+), 45 deletions(-) delete mode 100644 doc/docs.exs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 72ddfe11..553fb986 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,6 @@ jobs: - otp_version: 21 send_coverage: true run_dialyzer: true - build_docs: true - otp_version: 20 @@ -72,9 +71,6 @@ jobs: run: make dialyzer timeout-minutes: 8 - - if: matrix.build_docs - run: make doc - - if: matrix.send_coverage && success() run: ./rebar3 as test coveralls send env: @@ -124,6 +120,39 @@ jobs: - if: ${{ !matrix.skip }} run: make test_${{ matrix.json_lib }} + test_docs: + name: Test generating documentation + runs-on: ubuntu-latest + + strategy: + matrix: + include: + - elixir: 1.15.x + otp_version: 26 + rebar3: '3.22.1' + # hdr_histogram NIF requires the below PR to be merged to build on OTP 26 + # https://github.com/HdrHistogram/hdr_histogram_erl/pull/44 + erl_hist: true + + steps: + - uses: actions/checkout@v3 + - uses: erlef/setup-beam@v1 + with: + otp-version: ${{matrix.otp_version}} + elixir-version: ${{matrix.elixir}} + rebar3-version: ${{matrix.rebar3}} + + - if: matrix.erl_hist + run: echo "XPROF_ERL_HIST=true" >> $GITHUB_ENV + + - name: Cache hex packages + uses: actions/cache@v3 + with: + path: $HOME/.cache/rebar3 + key: ${{ matrix.otp_version }}-rebar3-cache + + - run: make gen_ex_doc + test_elixir: name: Test with Elixir (Elixir ${{matrix.elixir}} | OTP ${{matrix.otp_version}}) runs-on: ${{matrix.os}} diff --git a/Makefile b/Makefile index 57b0e682..f906283b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ JS_PRIV=apps/xprof_gui/priv BIN_DIR:=node_modules/.bin -VERSION:=$(shell grep vsn apps/xprof/src/xprof.app.src | cut -d '"' -f 2) REBAR3?=$(shell which rebar3 || echo ./rebar3) # this will update cowboy version based on rebar.config overwriting the lock file @@ -63,16 +62,19 @@ test_thoas: doc: $(REBAR3) edoc -~/.mix/escripts/ex_doc: - mix escript.install hex ex_doc --force - ./doc/src/readme.md: README.md sed -e 's|(doc/src/querysyntax.md)|(querysyntax.html)|' \ -e 's|doc/assets/|assets/|' \ -e '1 s|\[!\[.*||' README.md > ./doc/src/readme.md -gen_ex_doc: ~/.mix/escripts/ex_doc ./doc/docs.exs ./doc/src/readme.md ./doc/src/querysyntax.md - ~/.mix/escripts/ex_doc XProf $(VERSION) "doc/ebin" -c ./doc/docs.exs +gen_ex_doc: ./doc/src/readme.md + $(MAYBE_UPDATE_COWBOY) + $(MAYBE_UNLOCK_HIST) + $(REBAR3) ex_doc --app xprof_core + $(REBAR3) ex_doc --app xprof_gui + cp _build/docs/lib/xprof_core/ebin/xprof_core.beam _build/docs/lib/xprof/ebin + cp _build/docs/lib/xprof_gui/ebin/xprof_gui_rest.beam _build/docs/lib/xprof/ebin + $(REBAR3) ex_doc --app xprof dialyzer: $(MAYBE_UPDATE_COWBOY) @@ -82,4 +84,7 @@ dialyzer: publish: $(REBAR3) as publish hex publish --deps_from_config -.PHONY: compile dev dev_back_end dev_front_end npm bootstrap_front_end test_front_end build_prod_front_end test doc gen_ex_doc dialyzer publish +publish_docs: gen_ex_doc + $(REBAR3) as publish hex docs + +.PHONY: compile dev dev_back_end dev_front_end npm bootstrap_front_end test_front_end build_prod_front_end test doc gen_ex_doc dialyzer publish publish_docs diff --git a/apps/xprof/src/xprof.app.src b/apps/xprof/src/xprof.app.src index 0b5b5c4f..ee0e06a0 100644 --- a/apps/xprof/src/xprof.app.src +++ b/apps/xprof/src/xprof.app.src @@ -11,6 +11,7 @@ ,{env,[]} ,{modules, []} ,{files, ["rebar.config", "src/"]} + ,{doc, "doc"} ,{licenses, ["BSD-3-Clause"]} ,{maintainers, ["Marcin Kasprowicz", "Marcin Kolodziej", "Michal Niec", "Pawel Pikula", diff --git a/apps/xprof_core/src/test_module.erl b/apps/xprof_core/src/test_module.erl index 0c281e66..842c8997 100644 --- a/apps/xprof_core/src/test_module.erl +++ b/apps/xprof_core/src/test_module.erl @@ -1,6 +1,7 @@ %%% @doc Module to generate sample data %%% start tracing on `test_module:expensive_fun/1' %%% @end +%%% @private -module(test_module). -export([start/0]). diff --git a/apps/xprof_core/src/xprof_core.erl b/apps/xprof_core/src/xprof_core.erl index f823de48..6726990f 100644 --- a/apps/xprof_core/src/xprof_core.erl +++ b/apps/xprof_core/src/xprof_core.erl @@ -1,3 +1,6 @@ +%%% +%%% @doc Erlang API to core XProf functionality +%%% -module(xprof_core). -export([%% Autocomplete @@ -101,6 +104,7 @@ expand_query(Query) -> end. %% @doc Get loaded modules and functions (MFAs) that match the query string. +%% %% Used for autocomplete suggestions on the GUI. -spec get_matching_mfas_pp(binary()) -> [MFA :: binary()]. get_matching_mfas_pp(Query) -> @@ -116,7 +120,9 @@ monitor_pp(Query) -> monitor_pp(Query, []). %% @doc Start monitoring based on the specified query string with additional -%% parameters. Additional parameters have precedence overthe same keys in the +%% parameters. +%% +%% Additional parameters have precedence overthe same keys in the %% query. -spec monitor_pp(binary(), [{binary(), binary()}]) -> ok | {error, Reason :: already_traced | string()}. @@ -145,7 +151,9 @@ get_all_monitored() -> xprof_core_tracer:all_monitored(). %% @doc Return metrics gathered for the given function since the given -%% timestamp. Each item contains a timestamp and the corresponding histogram +%% timestamp. +%% +%% Each item contains a timestamp and the corresponding histogram %% metrics values. -spec get_data(xprof_core:mfa_id(), timestamp()) -> [Item] | {error, not_found} when Item :: [{time, timestamp()} | {HistKey, number()}], @@ -155,6 +163,8 @@ get_all_monitored() -> get_data(MFA, TimeStamp) -> xprof_core_trace_handler:data(MFA, TimeStamp). +%% @doc Return metrics gathered for the given function formatted +%% according to the active syntax mode. get_data_pp(MFA, TimeStamp) -> case xprof_core_trace_handler:data(MFA, TimeStamp) of {error, _} = Error -> @@ -177,7 +187,7 @@ get_called_funs(MFA) -> xprof_core_vm_info:get_called_funs(MFA). %% @doc Return list of called functions formatted according to the -%% active syntax mode +%% active syntax mode. -spec get_called_funs_pp(xprof_core:mfa_id()) -> [MFA :: binary()]. get_called_funs_pp(MFA) -> ModeCb = xprof_core_lib:get_mode_cb(), @@ -188,14 +198,16 @@ get_called_funs_pp(MFA) -> %% Global trace status %% -%% @doc Turn on tracing for one or all processes. Additionally tracing can be -%% paused and resumed for the same process specification (one or all) that was -%% given earlier. +%% @doc Turn on tracing for one or all processes. +%% +%% Additionally tracing can be paused and resumed for the same process +%% specification (one or all) that was given earlier. -spec trace(pid() | all | pause | resume) -> ok. trace(PidOrSpec) -> xprof_core_tracer:trace(PidOrSpec). %% @doc Return current tracing state. +%% %% (The `initialized' status is basically the same as `paused', additionally %% meaning that no tracing was started yet since xprof was started) -spec get_trace_status() -> {pid() | all, Status :: initialized | running | paused | overflow}. @@ -239,6 +251,7 @@ get_captured_data_pp(MFA, Offset) -> Error end. +%% @private args_res2proplist({Index, Pid, CallTime, Args, Res}, ModeCb) -> [{id, Index}, {pid, ModeCb:fmt_term(Pid)}, @@ -246,6 +259,7 @@ args_res2proplist({Index, Pid, CallTime, Args, Res}, ModeCb) -> {args, ModeCb:fmt_term(Args)}, {res, format_result(Res, ModeCb)}]. +%% @private format_result({return_from, Term}, ModeCb) -> ModeCb:fmt_term(Term); format_result({exception_from, {Class, Reason}}, ModeCb) -> @@ -284,20 +298,22 @@ rr(Mod) -> xprof_core_records:load_records(Mod). %% @doc Remove all record definitions. -%% (similar to shell command ```rf('_')''') +%% (similar to shell command `` rf('_') '') -spec rf() -> ok. rf() -> xprof_core_records:forget_records(). -%% @doc Remove selected record definitions. RecNames is a record name or a -%% list of record names. To remove all record definitions, use '_'. +%% @doc Remove selected record definitions. +%% +%% The argument can be a record name or a list of record names. To +%% remove all record definitions, use `` '_' ''. %% (similar to shell command `rf/1') -spec rf(atom() | [atom()]) -> ok. rf(RecNameOrNames) -> xprof_core_records:forget_records(RecNameOrNames). %% @doc Return all stored record definitions. -%% (Similar to shell command `rl()') +%% (Similar to shell command `rl/0') -spec rl() -> [tuple()]. rl() -> xprof_core_records:get_record_defs(). @@ -311,7 +327,9 @@ rl() -> set_mode(Mode) -> xprof_core_lib:set_mode(Mode). -%% @doc Get syntax mode, if not set explicitly it will be autodetected. +%% @doc Get syntax mode. +%% +%% If not set explicitly it will be autodetected. -spec get_mode() -> xprof_core:mode(). get_mode() -> xprof_core_lib:get_mode(). diff --git a/apps/xprof_core/src/xprof_core_app.erl b/apps/xprof_core/src/xprof_core_app.erl index a43e3798..7606bc50 100644 --- a/apps/xprof_core/src/xprof_core_app.erl +++ b/apps/xprof_core/src/xprof_core_app.erl @@ -1,5 +1,6 @@ %% @doc XProf Core application callback %% @end +%% @private -module(xprof_core_app). -behaviour(application). diff --git a/apps/xprof_core/src/xprof_core_cmd.erl b/apps/xprof_core/src/xprof_core_cmd.erl index 714f3d63..46b48693 100644 --- a/apps/xprof_core/src/xprof_core_cmd.erl +++ b/apps/xprof_core/src/xprof_core_cmd.erl @@ -8,6 +8,7 @@ %%% - other -> no trace_pattern -> xprof_core_tracer should find out where to send trace based on trace tag (maybe) %%% -> can only be turned off by trace/3 %%% - cmd id = ??? (single tracer per cmd-name or trace tag) +%%% @private -module(xprof_core_cmd). -export([expand_query/1, @@ -28,7 +29,7 @@ %% Convert param value from syntax-tree format to Erlang term or expression %% (Useful to implement some syntactic sugar/shorthands) --callback param_from_ast(Key :: atom(), Ast :: erl_parse:syntax_tree()) -> +-callback param_from_ast(Key :: atom(), Ast :: erl_parse:abstract_expr()) -> {ok, Value :: term()} | {error, Reason :: term()}. %% Validate param value and optionally convert to internal format diff --git a/apps/xprof_core/src/xprof_core_cmd_argdist.erl b/apps/xprof_core/src/xprof_core_cmd_argdist.erl index a6c16a4d..78bf48d4 100644 --- a/apps/xprof_core/src/xprof_core_cmd_argdist.erl +++ b/apps/xprof_core/src/xprof_core_cmd_argdist.erl @@ -1,3 +1,4 @@ +%% @private -module(xprof_core_cmd_argdist). -behaviour(xprof_core_cmd). diff --git a/apps/xprof_core/src/xprof_core_cmd_funlatency.erl b/apps/xprof_core/src/xprof_core_cmd_funlatency.erl index f84b2eca..b3f94676 100644 --- a/apps/xprof_core/src/xprof_core_cmd_funlatency.erl +++ b/apps/xprof_core/src/xprof_core_cmd_funlatency.erl @@ -1,3 +1,4 @@ +%% @private -module(xprof_core_cmd_funlatency). -export([mandatory_params/0, diff --git a/apps/xprof_core/src/xprof_core_elixir_syntax.erl b/apps/xprof_core/src/xprof_core_elixir_syntax.erl index 6c2cfd8b..ad800589 100644 --- a/apps/xprof_core/src/xprof_core_elixir_syntax.erl +++ b/apps/xprof_core/src/xprof_core_elixir_syntax.erl @@ -1,6 +1,7 @@ %%% %%% @doc Module to parse and format expressions in Elixir syntax %%% +%%% @private -module(xprof_core_elixir_syntax). -behaviour(xprof_core_language). @@ -25,7 +26,7 @@ %% Elixir quoted expressions -type ex_quoted() :: tuple() | ex_literal(). --type ex_literal() :: atom() | number() | binary() | fun((...) -> any()) | {any(), any()} | [any()]. +-type ex_literal() :: atom() | number() | binary() | fun() | {any(), any()} | list(). %% Erlang abstract syntax tree -type erl_ast() :: tuple(). diff --git a/apps/xprof_core/src/xprof_core_erlang_syntax.erl b/apps/xprof_core/src/xprof_core_erlang_syntax.erl index 0e74e494..24f66f3e 100644 --- a/apps/xprof_core/src/xprof_core_erlang_syntax.erl +++ b/apps/xprof_core/src/xprof_core_erlang_syntax.erl @@ -1,6 +1,7 @@ %%% %%% @doc Module to parse and format expressions in Erlang syntax %%% +%%% @private -module(xprof_core_erlang_syntax). -behaviour(xprof_core_language). diff --git a/apps/xprof_core/src/xprof_core_hist.erl b/apps/xprof_core/src/xprof_core_hist.erl index 9f005c4c..279caedf 100644 --- a/apps/xprof_core/src/xprof_core_hist.erl +++ b/apps/xprof_core/src/xprof_core_hist.erl @@ -29,6 +29,7 @@ %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE %%% SOFTWARE. +%%% @private -module(xprof_core_hist). -export([new/2, diff --git a/apps/xprof_core/src/xprof_core_language.erl b/apps/xprof_core/src/xprof_core_language.erl index d759c3d5..4d0118c5 100644 --- a/apps/xprof_core/src/xprof_core_language.erl +++ b/apps/xprof_core/src/xprof_core_language.erl @@ -2,6 +2,7 @@ %%% @doc Callback functions that need to be implemented %%% for a language-specific behaviour %%% +%%% @private -module(xprof_core_language). %% Function for start monitoring @@ -47,7 +48,7 @@ -callback fmt_param(xprof_core:param_name()) -> Formatted :: binary(). --callback fmt_param_and_delim(xprof_core:param()) -> +-callback fmt_param_and_delim(xprof_core:param_name()) -> Formatted :: binary(). -callback fmt_exception(Class :: throw | error | exit, Reason :: term()) -> diff --git a/apps/xprof_core/src/xprof_core_lib.erl b/apps/xprof_core/src/xprof_core_lib.erl index 2b5cbd6b..8c51cb83 100644 --- a/apps/xprof_core/src/xprof_core_lib.erl +++ b/apps/xprof_core/src/xprof_core_lib.erl @@ -1,3 +1,4 @@ +%% @private -module(xprof_core_lib). -export([mfaspec2atom/1, diff --git a/apps/xprof_core/src/xprof_core_ms.erl b/apps/xprof_core/src/xprof_core_ms.erl index 2e545382..365e1e98 100644 --- a/apps/xprof_core/src/xprof_core_ms.erl +++ b/apps/xprof_core/src/xprof_core_ms.erl @@ -1,3 +1,4 @@ +%% @private -module(xprof_core_ms). -export([fun2ms/1, diff --git a/apps/xprof_core/src/xprof_core_query.erl b/apps/xprof_core/src/xprof_core_query.erl index 3a202365..4960e78c 100644 --- a/apps/xprof_core/src/xprof_core_query.erl +++ b/apps/xprof_core/src/xprof_core_query.erl @@ -1,3 +1,4 @@ +%% @private -module(xprof_core_query). -export([param_to_term/1, diff --git a/apps/xprof_core/src/xprof_core_records.erl b/apps/xprof_core/src/xprof_core_records.erl index 9de09945..4c409c3a 100644 --- a/apps/xprof_core/src/xprof_core_records.erl +++ b/apps/xprof_core/src/xprof_core_records.erl @@ -1,4 +1,5 @@ %%% @doc Server to store loaded record definitions. +%%% @private -module(xprof_core_records). -export([start_link/0, diff --git a/apps/xprof_core/src/xprof_core_sup.erl b/apps/xprof_core/src/xprof_core_sup.erl index c7f1fe9f..02d4f2b3 100644 --- a/apps/xprof_core/src/xprof_core_sup.erl +++ b/apps/xprof_core/src/xprof_core_sup.erl @@ -1,4 +1,5 @@ %% @doc xprof top level supervisor. +%% @private -module(xprof_core_sup). -behaviour(supervisor). diff --git a/apps/xprof_core/src/xprof_core_trace_handler.erl b/apps/xprof_core/src/xprof_core_trace_handler.erl index 705fd27e..b3ca1538 100644 --- a/apps/xprof_core/src/xprof_core_trace_handler.erl +++ b/apps/xprof_core/src/xprof_core_trace_handler.erl @@ -5,6 +5,7 @@ %% registers itself localy under a atom that consists of MFA and xprof_ %% prefix. The same name is used to create public ETS table that holds entries %% with call time stats for every second. +%% @private -module(xprof_core_trace_handler). -behaviour(gen_server). diff --git a/apps/xprof_core/src/xprof_core_trace_handler_sup.erl b/apps/xprof_core/src/xprof_core_trace_handler_sup.erl index 8c1875e9..daa052a4 100644 --- a/apps/xprof_core/src/xprof_core_trace_handler_sup.erl +++ b/apps/xprof_core/src/xprof_core_trace_handler_sup.erl @@ -1,4 +1,5 @@ %%% @doc Supervisor +%%% @private -module(xprof_core_trace_handler_sup). -behaviour(supervisor). diff --git a/apps/xprof_core/src/xprof_core_tracer.erl b/apps/xprof_core/src/xprof_core_tracer.erl index e090464f..01694ffb 100644 --- a/apps/xprof_core/src/xprof_core_tracer.erl +++ b/apps/xprof_core/src/xprof_core_tracer.erl @@ -1,5 +1,6 @@ %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- %% ex: ts=4 sw=4 et +%% @private -module(xprof_core_tracer). diff --git a/apps/xprof_core/src/xprof_core_vm_info.erl b/apps/xprof_core/src/xprof_core_vm_info.erl index 4055f5b9..79c18e83 100644 --- a/apps/xprof_core/src/xprof_core_vm_info.erl +++ b/apps/xprof_core/src/xprof_core_vm_info.erl @@ -1,3 +1,4 @@ +%% @private -module(xprof_core_vm_info). -include_lib("compiler/src/beam_disasm.hrl"). diff --git a/doc/docs.exs b/doc/docs.exs deleted file mode 100644 index 4c6fb91b..00000000 --- a/doc/docs.exs +++ /dev/null @@ -1,13 +0,0 @@ -[ - main: "readme", - extras: ["doc/src/readme.md", - "doc/src/querysyntax.md": [title: "Query Syntax"], - "doc/src/commands.md": [] - ], - api_reference: false, - output: "doc/html/", - assets: "doc/assets", - logo: "./apps/xprof_gui/priv/build/xprof_icon.png", - source_url: "https://github.com/Appliscale/xprof", - homepage_url: "http://xprof.appliscale.io", -] diff --git a/doc/src/commands.md b/doc/src/commands.md index ede35cc8..70990566 100644 --- a/doc/src/commands.md +++ b/doc/src/commands.md @@ -24,7 +24,7 @@ error ``` ```elixir -%funlatency retmatch: {:error, _}, +%Funlatency retmatch: {:error, _}, mfa: Client.req/2 ``` @@ -41,7 +41,7 @@ non-empty list. ``` ```elixir -%funlatency retmatch: fn({:ok, [_|_]}) -> false; +%Funlatency retmatch: fn({:ok, [_|_]}) -> false; (_)-> true end, mfa: Client.req(id, _) -> message(id) ``` @@ -58,7 +58,7 @@ but only captures the first element. ``` ```elixir -%funlatency retmatch: fn([h|_]) -> {true, h} end, +%Funlatency retmatch: fn([h|_]) -> {true, h} end, mfa: Client.req/2 ``` @@ -90,6 +90,6 @@ request map can take at runtime: ``` ```elixir -%argdist enum: 5, +%Argdist enum: 5, mfa: Client.req(req) -> message(map_get(:cmp_id, req)) ``` diff --git a/doc/src/querysyntax.md b/doc/src/querysyntax.md index 2d33b4e0..80cc745e 100644 --- a/doc/src/querysyntax.md +++ b/doc/src/querysyntax.md @@ -26,7 +26,8 @@ give a function definition instead of arity. This gives the user the full power of match specifications and can be used both to selectively measure duration of function calls that match complicated filters and to capture only part of the arguments. The function has the same -limitations as `dbg:fun2ms/1`. (See [Match Specifications in +limitations as [`dbg:fun2ms/1`](https://www.erlang.org/doc/apps/runtime_tools/dbg.html#fun2ms/1). +(See [Match Specifications in Erlang](http://erlang.org/doc/apps/erts/match_spec.html) and [ms\_transform](http://erlang.org/doc/man/ms_transform.html)). @@ -113,7 +114,7 @@ simple query or an XProf-flavoured match-spec fun. The Erlang syntax is similar to a record, ```erlang -#cmd param1: {"val", 1}, mfa: mod:fun(_) +#cmd param1 = {"val", 1}, mfa = mod:fun(_) ``` while the Elixir syntax is similar to a struct, both without the curly brackets. diff --git a/rebar.config b/rebar.config index 52b4c5b5..acaa7cc7 100644 --- a/rebar.config +++ b/rebar.config @@ -27,8 +27,11 @@ {dev, [ %% {deps, [ {sync, "0.1.3"} ]} ]}, + {docs, + [{minimum_otp_vsn, "24.0"} %% edoc can generate doc chunks since OTP 24 + ]}, {publish, - [{plugins, [ {rebar3_hex, {git, "https://github.com/gomoripeti/rebar3_hex.git", {tag, "deps-3"}}} ]} + [{plugins, [ {rebar3_hex, {git, "https://github.com/gomoripeti/rebar3_hex.git", {tag, "deps-4"}}} ]} ]} ]}. @@ -36,3 +39,18 @@ {cover_export_enabled, true}. {coveralls_coverdata, [ "_build/test/cover/eunit.coverdata", "_build/test/cover/ct.coverdata" ]}. + +{project_plugins, [rebar3_ex_doc]}. +{ex_doc, [{main, "readme"}, + {extras, ["doc/src/readme.md", + {"doc/src/querysyntax.md", #{title => "Query Syntax"}}, + "doc/src/commands.md" + ]}, + {api_reference, false}, + {assets, #{<<"doc/assets">> => <<"assets">>}}, + {logo, "apps/xprof_gui/priv/build/xprof_icon.png"}, + {proglang, erlang}, + {source_url, "https://github.com/Appliscale/xprof"}, + {homepage_url, "http://xprof.appliscale.io"}, + {prefix_ref_vsn_with_v, false} + ]}. From d5cda713f350f3e55a024b80008ecebaf35ae700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20G=C3=B6m=C3=B6ri?= Date: Mon, 8 Jun 2026 20:56:17 +0200 Subject: [PATCH 3/5] Project plugin ex_doc doesn't compile on OTP 20 and below Revert when dropping support for OTP 20 --- Makefile | 6 +++--- rebar.config | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index f906283b..239de544 100644 --- a/Makefile +++ b/Makefile @@ -70,11 +70,11 @@ doc: gen_ex_doc: ./doc/src/readme.md $(MAYBE_UPDATE_COWBOY) $(MAYBE_UNLOCK_HIST) - $(REBAR3) ex_doc --app xprof_core - $(REBAR3) ex_doc --app xprof_gui + $(REBAR3) as docs ex_doc --app xprof_core + $(REBAR3) as docs ex_doc --app xprof_gui cp _build/docs/lib/xprof_core/ebin/xprof_core.beam _build/docs/lib/xprof/ebin cp _build/docs/lib/xprof_gui/ebin/xprof_gui_rest.beam _build/docs/lib/xprof/ebin - $(REBAR3) ex_doc --app xprof + $(REBAR3) as docs ex_doc --app xprof dialyzer: $(MAYBE_UPDATE_COWBOY) diff --git a/rebar.config b/rebar.config index acaa7cc7..153d3586 100644 --- a/rebar.config +++ b/rebar.config @@ -28,7 +28,12 @@ [ %% {deps, [ {sync, "0.1.3"} ]} ]}, {docs, - [{minimum_otp_vsn, "24.0"} %% edoc can generate doc chunks since OTP 24 + %% rebar3_ex_doc is only needed to generate docs (make gen_ex_doc) and + %% does not compile on older OTP, so it is scoped to this profile rather + %% than declared as a global project plugin. Move back to project_plugins when + %% OTP 23 and below dropped. + [{minimum_otp_vsn, "24.0"}, %% edoc can generate doc chunks since OTP 24 + {plugins, [rebar3_ex_doc]} ]}, {publish, [{plugins, [ {rebar3_hex, {git, "https://github.com/gomoripeti/rebar3_hex.git", {tag, "deps-4"}}} ]} @@ -40,7 +45,6 @@ {coveralls_coverdata, [ "_build/test/cover/eunit.coverdata", "_build/test/cover/ct.coverdata" ]}. -{project_plugins, [rebar3_ex_doc]}. {ex_doc, [{main, "readme"}, {extras, ["doc/src/readme.md", {"doc/src/querysyntax.md", #{title => "Query Syntax"}}, From ea16edf8731197a10dbad25ee2844e88319e3035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20G=C3=B6m=C3=B6ri?= Date: Mon, 8 Jun 2026 21:08:11 +0200 Subject: [PATCH 4/5] Run OTP 18-20 in a separate legacy CI job with git checkout Because the glibc found in erlang-18 to 20 containers is too old to run nodejs 20 github actions. Also don't run json CI tests on OTP 19 only on OTP 21. --- .github/workflows/ci.yml | 70 +++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 553fb986..5d2882ee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,19 +34,6 @@ jobs: send_coverage: true run_dialyzer: true - - otp_version: 20 - - - otp_version: 19 - - - otp_version: 19 - erl_hist: true - - - otp_version: 18 - # old_rebar fails with "Package not found in registry: {<<"hdr_histogram">>,<<"0.5.0">>}." - # with hdr_histogram NIF: xprof_core_hist_SUITE: Segmentation fault (core dumped) - erl_hist: true - old_cowboy: true - steps: - uses: actions/checkout@v3 @@ -77,48 +64,73 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} continue-on-error: true - test_json_lib: - name: Test different json lib (${{ matrix.json_lib }} | OTP ${{ matrix.otp_version }}) + # Same as the "test" job but for OTP 18-20, whose containers ship a glibc + # too old for the node20 runtime that actions/checkout and actions/cache + # now require. This job checks out with plain git and skips the cache. + test_legacy: + name: OTP ${{ matrix.otp_version }} (legacy) runs-on: ubuntu-latest - container: erlang:${{ matrix.otp_version }} strategy: fail-fast: false matrix: - otp_version: [19, 21] - json_lib: [jiffy, jsx, thoas] include: + - otp_version: 20 + - otp_version: 19 - old_cowboy: true - # thoas requires OTP 21+ - otp_version: 19 - json_lib: thoas - skip: true + erl_hist: true - # fails with "Package not found in registry: jiffy-1.1.0." - #- otp_version: 18 - # old_rebar: true - # old_cowboy: true + - otp_version: 18 + # old_rebar fails with "Package not found in registry: {<<"hdr_histogram">>,<<"0.5.0">>}." + # with hdr_histogram NIF: xprof_core_hist_SUITE: Segmentation fault (core dumped) + erl_hist: true + old_cowboy: true steps: - - uses: actions/checkout@v3 + - name: Checkout with git (avoids node-based actions on old glibc) + run: | + git config --global --add safe.directory $GITHUB_WORKSPACE + git init -q + git remote add origin "https://github.com/${{ github.repository }}" + git fetch -q --depth 1 origin "${{ github.ref }}" + git checkout -q FETCH_HEAD - if: matrix.old_rebar run: echo "REBAR3=./rebar3" >> $GITHUB_ENV + - if: matrix.erl_hist + run: echo "XPROF_ERL_HIST=true" >> $GITHUB_ENV + - if: matrix.old_cowboy run: echo "COWBOY_VERSION=1.1.2" >> $GITHUB_ENV + - run: make test + + test_json_lib: + name: Test different json lib (${{ matrix.json_lib }} | OTP ${{ matrix.otp_version }}) + runs-on: ubuntu-latest + + container: erlang:${{ matrix.otp_version }} + + strategy: + fail-fast: false + matrix: + otp_version: [21] + json_lib: [jiffy, jsx, thoas] + + steps: + - uses: actions/checkout@v3 + - name: Cache hex packages uses: actions/cache@v3 with: path: $HOME/.cache/rebar3 key: ${{ matrix.otp_version }}-rebar3-cache-json-lib - - if: ${{ !matrix.skip }} - run: make test_${{ matrix.json_lib }} + - run: make test_${{ matrix.json_lib }} test_docs: name: Test generating documentation From 15f62f67f5950bcbd23d11a3cccd2ed0cfdcac08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20G=C3=B6m=C3=B6ri?= Date: Tue, 9 Jun 2026 23:46:26 +0200 Subject: [PATCH 5/5] Remove old Elixir versions from CI (1.5-1.10) - Elixir 1.4 with OTP 18: runner ubuntu-20.4 is only compatible with OTP 20+ earlier OTP versions fail with: no match of right hand side value: {:error, {:ssl, {'no such file or directory', 'ssl.app'}}} running ubuntu-18.4 was removed on 2022.04.03 https://github.com/actions/runner-images/issues/6002 - Elixir 1.5-1.10 runner-24.04 is only compatible with OTP 24.3+ (runner-22.04 is only compatible with OTP 24.2+) running ubuntu-20.04 was removed on 2025.04.15 https://github.com/actions/runner-images/issues/11101 https://github.blog/changelog/2025-01-15-github-actions-ubuntu-20-runner-image-brownout-dates-and-other-breaking-changes/ - OTP 24 is first supported by Elixir 1.11.4 --- .github/workflows/ci.yml | 55 ++++------------------------------------ 1 file changed, 5 insertions(+), 50 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d2882ee..33295aec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -172,60 +172,15 @@ jobs: fail-fast: false matrix: include: - # runner ubuntu-20.4 is only compatible with OTP 20+ - # earlier OTP versions fail with: - # no match of right hand side value: {:error, {:ssl, {'no such file or directory', 'ssl.app'}}} - # running ubuntu-18.4 was removed on 2022.04.03 - # https://github.com/actions/runner-images/issues/6002 - # - elixir: 1.4.x - # otp_version: 18 - # rebar3: '3.7.4' - # old_cowboy: true - # # with hdr_histogram NIF: xprof_core_hist_SUITE: Segmentation fault (core dumped) - # erl_hist: true - # os: ubuntu-18.04 - - - elixir: 1.5.x - otp_version: 20 - rebar3: '3.7.4' - old_cowboy: true - erl_hist: true - os: ubuntu-20.04 - - - elixir: 1.6.x - otp_version: 20 - rebar3: '3.15.2' - os: ubuntu-20.04 - - - elixir: 1.7.x - otp_version: 20 - rebar3: '3.15.2' - os: ubuntu-20.04 - - - elixir: 1.8.x - otp_version: 20 - rebar3: '3.15.2' - os: ubuntu-20.04 - - - elixir: 1.9.x - otp_version: 20 - rebar3: '3.15.2' - os: ubuntu-20.04 - - - elixir: 1.10.x - otp_version: 21 - rebar3: '3.15.2' - os: ubuntu-20.04 - - - elixir: 1.11.x - otp_version: 22 + - elixir: 1.11.4 + otp_version: 24 rebar3: '3.18.0' - os: ubuntu-20.04 + os: ubuntu-latest - elixir: 1.12.x - otp_version: 23 + otp_version: 24 rebar3: '3.19.0' - os: ubuntu-20.04 + os: ubuntu-latest - elixir: 1.13.x otp_version: 24