diff --git a/.github/workflows/erlang.yml b/.github/workflows/erlang.yml index aa193ea..d169989 100644 --- a/.github/workflows/erlang.yml +++ b/.github/workflows/erlang.yml @@ -69,12 +69,12 @@ jobs: #!/bin/sh printf 29 SH - cat > /tmp/release/observer_cli-2.0.0-otp29 <<'SH' + cat > /tmp/release/observer_cli-2.1.0-otp29 <<'SH' #!/bin/sh - printf '%s\n' 'observer_cli 2.0.0' 'controller OTP 29' + printf '%s\n' 'observer_cli 2.1.0' 'controller OTP 29' SH - chmod +x /tmp/bin/curl /tmp/bin/erl /tmp/release/observer_cli-2.0.0-otp29 - (cd /tmp/release && sha256sum observer_cli-2.0.0-otp29 > SHA256SUMS) + chmod +x /tmp/bin/curl /tmp/bin/erl /tmp/release/observer_cli-2.1.0-otp29 + (cd /tmp/release && sha256sum observer_cli-2.1.0-otp29 > SHA256SUMS) HOME=/tmp/home PATH=/tmp/bin:/usr/bin:/bin sh /src/install.sh test -x /tmp/home/.local/bin/observer_cli SMOKE diff --git a/README.md b/README.md index dd247b4..b932727 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://github.com/zhongwencool/observer_cli/workflows/ci/badge.svg)](https://github.com/zhongwencool/observer_cli/actions) [![codecov](https://codecov.io/gh/zhongwencool/observer_cli/branch/main/graph/badge.svg)](https://codecov.io/gh/zhongwencool/observer_cli) -[![GitHub tag](https://img.shields.io/github/tag/zhongwencool/observer_cli.svg)](https://github.com/zhongwencool/observer_cli) +[![GitHub tag](https://img.shields.io/github/tag/smartrent/observer_cli.svg)](https://github.com/smartrent/observer_cli) [![MIT License](https://img.shields.io/hexpm/l/observer_cli.svg)](https://hex.pm/packages/observer_cli) [![Hex.pm Version](https://img.shields.io/hexpm/v/observer_cli.svg)](https://hex.pm/packages/observer_cli) [![Hex.pm Downloads](https://img.shields.io/hexpm/dt/observer_cli.svg)](https://hex.pm/packages/observer_cli) @@ -24,7 +24,7 @@ process rankings](https://raw.githubusercontent.com/zhongwencool/observer_cli/8e ## Installation Install `observer_cli` in the target release so command diagnostics can run -there. Version 2.0 controllers require the matching `2.0.0` target bundle. +there. Version 2.1 controllers require the matching `2.1.0` target bundle. Observer CLI 2.0 supports Erlang/OTP 26–29. JSON output requires OTP 27 or newer on the controller; text and Erlang-term output work across the supported range. @@ -36,7 +36,7 @@ Add the dependency to `rebar.config`: ```erlang {deps, [ - {observer_cli, "2.0.0"} + {observer_cli, {git, "https://github.com/smartrent/observer_cli.git", {tag, "v2.1.0"}}} ]}. ``` @@ -53,7 +53,7 @@ Add the dependency to `mix.exs`: ```elixir defp deps do [ - {:observer_cli, "2.0.0"} + {:observer_cli, git: "https://github.com/smartrent/observer_cli", tag: "v2.1.0"}, ] end ``` @@ -79,7 +79,7 @@ On macOS or Linux, the versioned installer selects the escript for the local OTP major, verifies its release checksum, and installs it for the current user: ```sh -curl -fsSL https://raw.githubusercontent.com/zhongwencool/observer_cli/v2.0.0/install.sh | sh +curl -fsSL https://raw.githubusercontent.com/smartrent/observer_cli/v2.1.0/install.sh | sh ``` Add `$HOME/.local/bin` to `PATH` if the installer asks you to. @@ -89,9 +89,9 @@ Add `$HOME/.local/bin` to `PATH` if the installer asks you to. Build the same version from its release tag instead: ```sh -VERSION=2.0.0 +VERSION=2.1.0 git clone --branch "v${VERSION}" --depth 1 \ - https://github.com/zhongwencool/observer_cli.git + https://github.com/smartrent/observer_cli.git cd observer_cli ``` @@ -153,7 +153,7 @@ the response, and stops the controller before returning. - Explore the same node interactively through detailed TUI pages and plugins. The normative machine-readable response contract is published as -[`priv/schema/observer_cli.cli.v1.schema.json`](https://raw.githubusercontent.com/zhongwencool/observer_cli/v2.0.0/priv/schema/observer_cli.cli.v1.schema.json). +[`priv/schema/observer_cli.cli.v1.schema.json`](https://raw.githubusercontent.com/smartrent/observer_cli/v2.1.0/priv/schema/observer_cli.cli.v1.schema.json). ## Choose CLI or TUI @@ -162,7 +162,7 @@ The normative machine-readable response contract is published as | **CLI — recommended** | Production runbooks, automation, incident capture, and AI-agent workflows | `observer_cli diagnose` | | TUI | Live exploration, ranking changes, and detail drill-down | `observer_cli tui app@host` | -The CLI requires `observer_cli` 2.0.0 in the target release and does not inject +The CLI requires `observer_cli` 2.1.0 in the target release and does not inject missing diagnostic code. The TUI can load its matching interactive bundle on a trusted target before starting. The old bare `observer_cli NODE [COOKIE REFRESH_MS]` form is not supported; use the explicit diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 6563c2a..1ac2e78 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,20 @@ Release and maintenance changes, newest first. +## 2.1.0 + +- Added a `/proc` fallback for the Home and System `ps` fields on hosts whose + `ps` lacks `-o`, such as BusyBox on Nerves. `ps -o` support is probed once + per session, and the TUI no longer runs `ps` on every render when it is + missing. +- Shown `cpu rate` in place of `ps -o pcpu` on the fallback. It is a rate over + the refresh interval, not a lifetime average, and may exceed 100 on + multicore hosts. +- Relabelled the memory fields to `/proc pmem`, `/proc rss`, and `/proc vsz` + on the fallback, sourced from `VmRSS`, `VmSize`, and `MemTotal`. +- Redirected `ps` stderr to `/dev/null` so usage messages are not parsed as + output. + ## 2.0.0 (release candidate) - Added `mix escript.build` as an alternative source build for the controller, diff --git a/install.sh b/install.sh index ab6e619..d316a3e 100755 --- a/install.sh +++ b/install.sh @@ -2,8 +2,8 @@ set -eu -VERSION=2.0.0 -RELEASE_URL="https://github.com/zhongwencool/observer_cli/releases/download/v$VERSION" +VERSION=2.1.0 +RELEASE_URL="https://github.com/smartrent/observer_cli/releases/download/v$VERSION" INSTALL_DIR="$HOME/.local/bin" for cmd in curl erl escript awk install; do diff --git a/mix.exs b/mix.exs index d51a88d..76e293d 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule ObserverCli.MixProject do def project do [ app: :observer_cli, - version: "2.0.0", + version: "2.1.0", language: :erlang, description: "Production-ready BEAM diagnostics for operators, automation, and AI agents.", escript: [ diff --git a/scripts/escript-smoke.sh b/scripts/escript-smoke.sh index a470894..66ef374 100755 --- a/scripts/escript-smoke.sh +++ b/scripts/escript-smoke.sh @@ -129,7 +129,7 @@ check "short help" 0 "Usage:" empty -h check "otp-state help" 0 "observer_cli otp-state" empty otp-state --help check "logs help" 0 "observer_cli logs" empty logs --help check "trace call help" 0 "observer_cli trace call" empty trace call --help -check "version" 0 "observer_cli 2.0.0" empty --version +check "version" 0 "observer_cli 2.1.0" empty --version check "unknown option" 2 empty "observer_cli --help" --bogus check "removed positional TUI shorthand" 2 empty "unknown command: target@host" target@host check "removed gen-server-state command" 2 empty "unknown command: gen-server-state" gen-server-state init diff --git a/src/observer_cli.app.src b/src/observer_cli.app.src index f4df1d0..ec59a21 100644 --- a/src/observer_cli.app.src +++ b/src/observer_cli.app.src @@ -1,6 +1,6 @@ {application, observer_cli, [ {description, "Production-ready BEAM diagnostics for operators, automation, and AI agents."}, - {vsn, "2.0.0"}, + {vsn, "2.1.0"}, {modules, [observer_cli]}, {registered, []}, {applications, [kernel, stdlib, crypto, recon]}, diff --git a/src/observer_cli_lib.erl b/src/observer_cli_lib.erl index c931b05..b63e658 100644 --- a/src/observer_cli_lib.erl +++ b/src/observer_cli_lib.erl @@ -552,7 +552,7 @@ resolve_ps_cmd(Cmd, ParseOutput) -> _Accepted -> Cmd end. -%% @doc Reads one "Field: kB" line from /proc//status, e.g. VmRSS. +%% @doc Reads one "Field: <N> kB" line from /proc/<Pid>/status, e.g. VmRSS. -spec proc_status_field_kb(string(), string()) -> non_neg_integer() | undefined. proc_status_field_kb(Pid, Field) -> case file:read_file("/proc/" ++ Pid ++ "/status") of diff --git a/src/observer_cli_snapshot.erl b/src/observer_cli_snapshot.erl index b7bf9ac..562b700 100644 --- a/src/observer_cli_snapshot.erl +++ b/src/observer_cli_snapshot.erl @@ -162,7 +162,7 @@ -endif. -define(PROTOCOL_VERSION, 1). --define(BUNDLE_VERSION, <<"2.0.0">>). +-define(BUNDLE_VERSION, <<"2.1.0">>). -define(TARGET_MARGIN_MS, 1000). -define(WORKER_DOWN_TIMEOUT_MS, 100). -define(DEEP_FINISH_MARGIN_MS, 250). diff --git a/test/observer_cli_cli_test.erl b/test/observer_cli_cli_test.erl index 28db916..216728e 100644 --- a/test/observer_cli_cli_test.erl +++ b/test/observer_cli_cli_test.erl @@ -1337,7 +1337,7 @@ health_command_text_reports_test() -> ). command_text_and_error_encoding_test() -> - Capabilities = #{<<"protocol_version">> => 1, <<"bundle_version">> => <<"2.0.0">>}, + Capabilities = #{<<"protocol_version">> => 1, <<"bundle_version">> => <<"2.1.0">>}, ContextData = #{ <<"node">> => <<"target@host">>, <<"name_mode">> => <<"short">>, @@ -1456,7 +1456,7 @@ command_text_and_error_encoding_test() -> ). text_encoder_public_edge_contract_test() -> - Capabilities = #{<<"protocol_version">> => 1, <<"bundle_version">> => <<"2.0.0">>}, + Capabilities = #{<<"protocol_version">> => 1, <<"bundle_version">> => <<"2.1.0">>}, Incompatible = observer_cli_cli:response( connect, complete, diff --git a/test/observer_cli_escriptize_test.erl b/test/observer_cli_escriptize_test.erl index 688ab9c..2fb5b4b 100644 --- a/test/observer_cli_escriptize_test.erl +++ b/test/observer_cli_escriptize_test.erl @@ -1396,7 +1396,7 @@ command_help_test() -> 24, 80, [], fun() -> observer_cli_escriptize:main(["--version"]) end ), observer_cli_test_io:assert_stable_fragments(Version, [ - "observer_cli 2.0.0", "observer_cli.cli/v1", "protocol 1", "controller OTP" + "observer_cli 2.1.0", "observer_cli.cli/v1", "protocol 1", "controller OTP" ]), ?assertEqual(nonode@nohost, node()). @@ -3532,7 +3532,7 @@ dynamic_controller_handshake() -> RandomCookie = binary_to_atom(binary:encode_hex(RandomBytes)), try ?assertEqual( - {ok, #{bundle_version => <<"2.0.0">>, protocol_version => 1}}, + {ok, #{bundle_version => <<"2.1.0">>, protocol_version => 1}}, observer_cli_escriptize:connect_target( Target, shortnames, @@ -3589,7 +3589,7 @@ invalid_remote_dispatch_contract() -> << "-module(observer_cli_snapshot).\n" "-export([capabilities/0, dispatch/4]).\n" - "capabilities() -> #{bundle_version => <<\"2.0.0\">>, protocol_version => 1}.\n" + "capabilities() -> #{bundle_version => <<\"2.1.0\">>, protocol_version => 1}.\n" "dispatch(_, _, _, _) -> #{invalid => true}.\n" >> ), @@ -4055,7 +4055,7 @@ diagnose_escript_with_dispatch(Escript, Script, CookieEnv, ExitCode, DispatchRes Contents = io_lib:format( "-module(observer_cli_snapshot).~n" "-export([capabilities/0,dispatch/4]).~n" - "capabilities() -> #{bundle_version => <<\"2.0.0\">>, protocol_version => 1}.~n" + "capabilities() -> #{bundle_version => <<\"2.1.0\">>, protocol_version => 1}.~n" "dispatch(_,diagnose,_,_) -> ~s.~n", [DispatchResult] ), @@ -4354,12 +4354,12 @@ response_validation_boundaries_test() -> observer_cli_escriptize:capabilities(node(), 0) ), ?assertEqual( - {ok, #{bundle_version => <<"2.0.0">>, protocol_version => 1}}, + {ok, #{bundle_version => <<"2.1.0">>, protocol_version => 1}}, observer_cli_escriptize:capabilities(node(), 1000) ), ?assert( observer_cli_escriptize:compatible_capabilities(#{ - bundle_version => <<"2.0.0">>, protocol_version => 1, extra => supported + bundle_version => <<"2.1.0">>, protocol_version => 1, extra => supported }) ), ?assertNot(observer_cli_escriptize:compatible_capabilities(#{protocol_version => 1})), @@ -5128,7 +5128,7 @@ assert_partial_snapshot_exit(Escript, Script, CookieEnv) -> io_lib:format( "-module(observer_cli_snapshot).~n" "-export([capabilities/0,dispatch/4]).~n" - "capabilities() -> #{bundle_version => <<\"2.0.0\">>, protocol_version => 1}.~n" + "capabilities() -> #{bundle_version => <<\"2.1.0\">>, protocol_version => 1}.~n" "dispatch(_,snapshot,_,_) -> ~tp.~n", [ #{ diff --git a/test/observer_cli_snapshot_test.erl b/test/observer_cli_snapshot_test.erl index 9ca7041..67a5728 100644 --- a/test/observer_cli_snapshot_test.erl +++ b/test/observer_cli_snapshot_test.erl @@ -19,7 +19,7 @@ capabilities_test() -> Capabilities = observer_cli_snapshot:capabilities(), - ?assertEqual(#{bundle_version => <<"2.0.0">>, protocol_version => 1}, Capabilities), + ?assertEqual(#{bundle_version => <<"2.1.0">>, protocol_version => 1}, Capabilities), _ = application:load(observer_cli), {ok, Version} = application:get_key(observer_cli, vsn), ?assertEqual(list_to_binary(Version), maps:get(bundle_version, Capabilities)).