Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/erlang.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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.
Expand All @@ -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"}}}
]}.
```

Expand All @@ -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
```
Expand All @@ -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.
Expand All @@ -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
```

Expand Down Expand Up @@ -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

Expand All @@ -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
Expand Down
14 changes: 14 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand Down
2 changes: 1 addition & 1 deletion scripts/escript-smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/observer_cli.app.src
Original file line number Diff line number Diff line change
@@ -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]},
Expand Down
2 changes: 1 addition & 1 deletion src/observer_cli_lib.erl
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ resolve_ps_cmd(Cmd, ParseOutput) ->
_Accepted -> Cmd
end.

%% @doc Reads one "Field: <N> kB" line from /proc/<Pid>/status, e.g. VmRSS.
%% @doc Reads one "Field: &lt;N&gt; kB" line from /proc/&lt;Pid&gt;/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
Expand Down
2 changes: 1 addition & 1 deletion src/observer_cli_snapshot.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
4 changes: 2 additions & 2 deletions test/observer_cli_cli_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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">>,
Expand Down Expand Up @@ -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,
Expand Down
14 changes: 7 additions & 7 deletions test/observer_cli_escriptize_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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()).

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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"
>>
),
Expand Down Expand Up @@ -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]
),
Expand Down Expand Up @@ -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})),
Expand Down Expand Up @@ -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",
[
#{
Expand Down
2 changes: 1 addition & 1 deletion test/observer_cli_snapshot_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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)).
Expand Down