Giter Club home page Giter Club logo

observer_cli's Introduction


observer_cli

Build Status GitHub tag MIT License Hex.pm Version Hex.pm Downloads

Visualize Erlang/Elixir Nodes On The Command Line base on recon. Document in detail.

Goal

  • Provide a high-performance tool usable both in development and production settings.
  • Focus on important and detailed information about real-time running system.
  • Keep minimal consumption.

Installation

Erlang

%% rebar.config
{deps, [observer_cli]}
%% erlang.mk
dep_observer_cli = hex 1.7.4

Elixir

# mix.exs
   def deps do
     [{:observer_cli, "~> 1.7"}]
   end

How-To

Try in local shell.

%% rebar3 project
rebar3 shell
1> observer_cli:start().
%% mix project
iex -S mix
iex(1)> :observer_cli.start

Monitor remote node

%% rebar3 project
rebar3 shell --name '[email protected]'
1> observer_cli:start('target@host', 'magic_cookie').
%% mix project
iex --name "[email protected]" -S mix
iex(1)> :observer_cli.start(:'target@host', :'magic_cookie')

ensure observer_cli application been loaded on target node.

Try in Elixir 1.9.x release

%% create elixir release
mix release
%% rpc current node
_build/dev/rel/example/bin/example rpc ":observer_cli.start"

ensure observer_cli application been loaded on current node.

Escriptize

  1. cd path/to/observer_cli/
  2. rebar3 escriptize to generate an escript executable containing the project's and its dependencies' BEAM files. Place script(_build/default/bin/observer_cli) anywhere in your path and use observer_cli command.
  3. observer_cli TARGETNODE [TARGETCOOKIE REFRESHMS] to monitor remote node.

DEMO

Home

How to write your own plugin?

If you need to customize some of your internal metrics and integrate it into observer_ci, you only need to write a observer_cli_plugin behaviour in a few simple steps to get a nice presentation.

  1. Configure observer_cli,tell observer_cli how to find your plugin.
%% module       - Specific module implements plugin behavior. It's mandatory.
%% title        - Menu title. It's mandatory.
%% shortcut     - Switch plugin by shortcut. It's mandatory.
%% interval     - Refresh interval ms. It's optional. default is 1500ms.
%% sort_column  - Sort the sheet by this index. It's optional default is 2.

{plugins,
  [
    #{module => observer_cli_plug_behaviour_x, title => "XPlug",
      interval => 1600, shortcut => "X", sort_column => 3},
    #{module => observer_cli_plug_behaviour_y, title => "YPlug",
      interval =>2000, shortcut => "Y", sort_column => 3}
  ]
}

The main view is HOME by default(observer_cli:start()). If you want to plugin view as main view, DO:your_cli:start().

% your_cli.erl
start() -> observer_cli:start_plugin().
  1. Write observer_cli_plugin behaviour. observer_cli_plugin has 3 callbacks.

2.1 attributes.

-callback attributes(PrevState) -> {[Rows], NewState} when
    Rows :: #{content => string()|integer()|{byte, pos_integer()},
              width => pos_integer(), color => binary()}.

for example:

attributes(PrevState) ->
  Attrs = [
    [
      #{content => "XXX Ets Size", width => 15},
      #{content => 122, width => 10},
      #{content => "Memory Capcity", width => 15},
      #{content => {percent, 0.12}, width => 16},
      #{content => "XYZ1 Process Mem", width => 19},
      #{content => {byte, 1023 * 1203}, width => 19}
    ],
    [
      #{content => "YYY Ets Size", width => 15},
      #{content => 43, width => 10},
      #{content => "Disk Capcity", width => 15},
      #{content => {percent, 0.23}, width => 16},
      #{content => "XYZ2 Process Mem", width => 19},
      #{content => {byte, 2034 * 220}, width => 19}
    ],
    [
      #{content => "ZZZ Ets Size", width => 15},
      #{content => 108, width => 10},
      #{content => "Volume Capcity", width => 15},
      #{content => {percent, 0.101}, width => 16},
      #{content => "XYZ3 Process Mem", width => 19},
      #{content => {byte, 12823}, width => 19}
    ]
  ],
  NewState = PrevState,
  {Attrs, NewState}.
|Home(H)|XPlug(X)|YPlug(Y)| | 0Days 3:34:50 |
|XXX Ets Size | 122 | Memory Capcity | 12.00% | XYZ1 Process Mem | 1.1737 MB |
|YYY Ets Size | 43 | Disk Capcity | 23.00% | XYZ2 Process Mem | 436.9922 KB |
|ZZZ Ets Size | 108 | Volume Capcity | 10.10% | XYZ3 Process Mem | 12.5225 KB |
-callback sheet_header() -> [SheetHeader] when
    SheetHeader :: #{title => string(), width => pos_integer(), shortcut => string()}.

for example:

sheet_header() ->
  [
    #{title => "Pid", width => 15},
    #{title => "Register", width => 20},
    #{title => "Memory", width => 20, shortcut => "S"},
    #{title => "Reductions", width => 23, shortcut => "R"},
    #{title => "Message Queue Len", width => 23, shortcut => "Q"}
  ].
|No |Pid |Register |Memory(S) |Reductions(R) |Message Queue Len(Q) |
-callback sheet_body(PrevState) -> {[SheetBody], NewState} when
    PrevState :: any(),
    SheetBody :: list(),
    NewState :: any().

for example:

sheet_body(PrevState) ->
  Body = [
    begin
      Register =
        case erlang:process_info(Pid, registered_name) of
          [] -> [];
          {_, Name} -> Name
        end,
      [
        Pid,
        Register,
        {byte, element(2, erlang:process_info(Pid, memory))},
        element(2, erlang:process_info(Pid, reductions)),
        element(2, erlang:process_info(Pid, message_queue_len))
      ]
    end
    || Pid <- erlang:processes()
  ],
  NewState = PrevState,
  {Body, NewState}.

Support {byte, 1024*10} to 10.0000 KB; {percent, 0.12} to 12.00%.

|No |Pid |Register |Memory(S) |Reductions(R) |Message Queue Len(Q) |
|1 |<0.242.0> | | 4.5020 MB | 26544288 | 0 |
|2 | <0.206.0> | | 1.2824 MB | 13357885 | 0 |
|3 | <0.10.0> | erl_prim_loader | 1.0634 MB | 10046775 | 0 |
|4 | <0.434.0> | | 419.1719 KB | 10503690 | 0 |
|5 | <0.44.0> | application_contro | 416.6250 KB | 153598 | 0 |
|6 | <0.50.0> | code_server | 416.4219 KB | 301045 | 0 |
|7 | <0.9.0> | rebar_agent | 136.7031 KB | 1337603 | 0 |
|8 | <0.207.0> | | 99.3125 KB | 9629 | 0 |
|9 | <0.58.0> | file_server_2 | 41.3359 KB | 34303 | 0 |
|10 | <0.209.0> | | 27.3438 KB | 31210 | 0 |
|11 | <0.0.0> | init | 25.8516 KB | 8485 | 0 |
|refresh: 1600ms q(quit) Positive Number(set refresh interval time ms) F/B(forward/back) Current pages is 1 |

Support F/B to page up/down.

A more specific plugin can collect linux system information such as kernel vsn, loadavg, disk, memory usage, cpu utilization, IO statistics.


Changelog

  • 1.7.4

    • fix crash when ets:info/1 return undefined.
  • 1.7.3

    • fix system pane exception by ps command.
  • 1.7.2

    • Fix error when inspecting process that monitors via {RegName, Node}.
  • 1.7.1

    • application view show starting/loading/startPfalse/loaded/started application.
    • fixed badarg when staring by rpc and stop by ctrl+c.
    • fixed mix.exe version error
  • 1.7.0

    • application view support reductions/memory/process_count sort
    • plugin support {byte, 1024} to 10.0000 KB
    • plugin support {percent, 0.1234 to 12.34%
    • plugin support dig deep process view.
  • 1.6.2

    • fixed crash when ps command not found on windows.
  • 1.6.1

    • remove precise opt version
  • 1.6.0

    • hidden schedule usage default
    • format by erlformat
    • add ps -o pcpu,pmem,rss,vsz information
    • remove recon_alloc:memory/1 from HOME(too much cpu usage)
  • 1.5.4

    • Bump Recon to 2.5.1 for otp23 alloc compat.
  • 1.5.2

    • Use erlang:system_info(otp_release) when can't find OTP_VERSION file for the full version.
  • 1.5.1

    • Hide mnesia tab when it's not started
    • Show specific erl version such as '22.0.5'
  • 1.5.0

    • Bump Recon to 2.5.0
  • 1.4.5

    • Include a minimal mix.exs build file
    • Make sure EXIT message has been clear
  • 1.4.4

    • Make sure connection errors can be handled
  • 1.4.3

    • Bump Recon to 2.4.0
  • 1.4.2

    • Hidden schedule process bar when core > 100.
    • Allow to compile escript w/ inet6 based distribution.
    • Rewrite plugin callback, rename kv_label/0 to attributes/1.
  • 1.4.1

    • Fixed ets view memory usage wrong.
    • mnesia view memory usage According to bytes.
  • 1.4.0

    • Support write your own plugin.
  • 1.3.4

    • View(ets mnesia) support page down/up; support sort by memory or size.
    • Fixed pause crash.
    • Make refresh interval configurable.
  • 1.3.3

    • fixed io:format(Format,Args) Format not support iolist OTP R21
  • 1.3.2

    • Make sure all observer_cli process exit when quit.
    • Upgrade recon to 2.3.6
  • 1.3.1

    • Add atom limit/count in home.
    • Escript support short name and long name.
    • Fixed store process not exit.
    • Upgrade recon to 2.3.5
  • 1.3.0

    • Rewrite Network/Process view.
    • Support PageDown/PageUp for top n list.
    • Escript auto load observer_cli when it's not load on target node.
  • 1.2.2

    • fix schedule number >= 32 display wrong.
    • improve memory(byte/kilobyte/megabyte/gigabyte) unit.
  • 1.2.1

    • fixed autosize not work.
    • try best to make color adjust all platform.
  • 1.2.0

    • add application GUI.
    • Rearrange GUI and optimize render.
    • Always automatically adapt to the window size.
  • 1.1.0

    • Support escript, observer_cli <TARGETNODE> <COOKIE>
  • 1.0.9

    • Upgrade rebar3 to 3.3.3 for publish hex repo.

Contributors


zhongwencool

💻

Dimitrios Zorbas

💻

taotao

💻

Trevor Brown

💻

Zaiming Shi

💻

License

See the LICENSE file for license rights and limitations (MIT).

observer_cli's People

Contributors

alberdi avatar ansd avatar gomoripeti avatar keynslug avatar kianmeng avatar michaelklishin avatar michalmuskala avatar redink avatar sanmiguel avatar stratus3d avatar zhongwencool avatar zmstone avatar zorbash avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

observer_cli's Issues

could processes sort by msg queue length? thanks

||Pos|Pid | Memory| Name or Initial Call | Reductions|# Msg Queue |Current Function |
|1 |<0.1558.23> | 2546632| erlang:apply/2 | 47415|0 |shell:get_command1/5 |
|2 |<0.7074.23> | 1945520| erlang:apply/2 | 141245|0 |shell:eval_loop/3 |
|3 |<0.17146.14>| 1115320| lager_event | 127875168|0 |gen_event:fetch_msg/5 |

Ets view incorrectly displays memory usage

Hi, thanks for the great tool!

We found an issue with Ets view (the one activated with E) incorrectly displaying memory size of the tables. It would seem that the value displayed corresponds to the value in {memory, X} tuple returned by ets:info/1. However, that value is in machine words, not in bytes. Home view (activated with H) displays the correct size.

Error with OTP 23

When using OTP 23 and Elixir 1.10.3, I am getting the following error:

08:25:41.537 [error] Process #PID<7704.14084.1> on node :"[email protected]" raised an exception
** (ArgumentError) argument error
    :erlang.element(2, false)
    src/recon_alloc.erl:699: :recon_alloc.container_value/4
    src/recon_alloc.erl:671: :recon_alloc.container_size/3
    (stdlib 3.13) lists.erl:1239: :lists.map/2
    src/recon_alloc.erl:208: :recon_alloc.memory/2
    src/observer_cli.erl:616: :observer_cli.get_change_system_info/0
    src/observer_cli.erl:150: :observer_cli.redraw_running/7

Pressing ENTER I get this another error:

08:29:36.779 [error] Process #PID<7704.14191.1> on node :"[email protected]" raised an exception
** (ArgumentError) argument error
    :erlang.process_info(:undefined, [:registered_name, :dictionary, :group_leader, :status])
    src/recon.erl:235: :recon.proc_info/2
    src/recon.erl:223: :recon.info_type/3
    src/recon.erl:181: :recon."-info/1-lc$^0/1-0-"/2
    src/observer_cli_process.erl:34: :observer_cli_process.render_worker/6

output reports as serialized data

Observer CLI's reports use formatted ASCII and terminal control. Parsing this is certainly possible, but it would be far nicer (less hassle and possible error) if the reports could be made available in a serialized data format (e.g., Erlang Terms, GraphQL, JSON). Could this be added as an option?

io:format/2 calls stored in the release DEBUG log files

When connecting observer_cli escript to one of our VMs (Erlang 21.0), we noticed that all io:format/2 calls used by observer_cli where also send to our debug.log (we use the new Logger module) .

Then, the VM's CPU usage went super high.

Did anyone notice such a behavior?

Question around process list

Awesome work on this library! Very useful and well executed in my short time with it.

I may be missing something so wanted to ask. Is it possible to page/scroll through the process list to see additional processes, beyond what will fit in the buffer?

Cheers.

Lots of cores

I have a 64 vCPU machine with 128 schedulers set in vm.args (+S 128).

This is what my output looks like:

image

Plugin bytes conversion

Currently it seems I can only provide bytes as an integer. I am not sure how I should proceed to have the bytes formatted like the Home tab's Memory column for example 6.3586 MB. Is that something that is currently possible and if not, do you think it could be added?

Clarify the how to use instructions

Can we clarify the instructions to get this working? I'm using an elixir project, I've added {:observer_cli, "~> 1.3"}, to my defp deps and omitted :observer_cli from def application do as per https://www.amberbit.com/blog/2017/9/22/elixir-applications-vs-extra_applications-guide/

Then I run the local shell with rebar3 shell followed by observer_cli:start()., but then I get:

** exception error: undefined function observer_cli:start/0

Clearly I'm doing something wrong, but it's difficult to understand where this is the case. Can we add some more detail to the How To part of the readme to help people like me get started?

Menu shortcuts all change to uppercase

h(HOME)|e(ETS/SYS)|a(APP)|n(NET)|c(CARRIER)|db(MNESIA)|d(DOC)|
H(Home)|T(TableView)|A(Application)|N(Network)|M(MemoryAllocators)|DB(Mnesia)|D(Document)|

OTP 21 compatability?

When using OTP 21 and Elixir 1.6.6 I get the following:

:observer_cli.start()
[error] Error in process #PID<0.526.0> on node :"[email protected]" with exit value:
{:badarg, [{:erlang, :process_info, [:undefined, :message_queue_len], []}, {:observer_cli, :node_stats, 1, [file: '/Users/rlthompson/GitHub/vanguard/deps/observer_cli/src/observer_cli.erl', line: 579]}, {:observer_cli, :redraw_running, 7, [file: '/Users/rlthompson/GitHub/vanguard/deps/observer_cli/src/observer_cli.erl', line: 122]}]}

And when trying to connect to a remote node:

Node('[email protected]') refuse to be connected, make sure cookie is valid

Crash on Remote node while connecting

I am using observer_cli to monitor nodes. Erlang version is the latest one.
Observer_cli is dep_observer_cli = hex 1.5.1

Erlang/OTP 22 [erts-10.4.4] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:16] [hipe]

However I am getting this crash report

{{badmatch,{error,enoent}},[{observer_cli,get_stable_system_info,0,[{file,"src/observer_cli.erl"},{line,607}]},{observer_cli,render_worker,3,[{file,"src/observer_cli.erl"},{line,123}]}]}

-

{badarg,[{erlang,process_info,[undefined,[registered_name,dictionary,group_leader,status]],[]},{recon,proc_info,2,[{file,"src/recon.erl"},{line,235}]},{recon,info_type,3,[{file,"src/recon.erl"},{line,223}]},{recon,'-info/1-lc$^0/1-0-',2,[{file,"src/recon.erl"},{line,181}]},{observer_cli_process,render_worker,6,[{file,"src/observer_cli_process.erl"},{line,34}]}]}

Crash on HiPE compiled node

When using observer_cli (ba4c3a4) to attach to a node which contains HiPE compiled modules, observer_cli crashes with this:

{function_clause,[{observer_cli_lib,mfa_to_list,
                                    [undefined],
                                    [{file,"/observer_cli/_build/default/deps/observer_cli/src/observer_cli_lib.erl"},
                                     {line,107}]},
                  {observer_cli,get_current_initial_call,1,
                                [{file,"/observer_cli/_build/default/deps/observer_cli/src/observer_cli.erl"},
                                 {line,429}]},
                  {observer_cli,get_top_n_info,1,
                                [{file,"/observer_cli/_build/default/deps/observer_cli/src/observer_cli.erl"},
                                 {line,507}]},
                  {observer_cli,'-render_top_n_view/5-fun-0-',3,
                                [{file,"/observer_cli/_build/default/deps/observer_cli/src/observer_cli.erl"},
                                 {line,296}]},
                  {lists,foldl,3,[{file,"lists.erl"},{line,1263}]},
                  {observer_cli,top_n_rows,3,
                                [{file,"/observer_cli/_build/default/deps/observer_cli/src/observer_cli.erl"},
                                 {line,400}]},
                  {observer_cli,render_top_n_view,5,
                                [{file,"/observer_cli/_build/default/deps/observer_cli/src/observer_cli.erl"},
                                 {line,308}]},
                  {observer_cli,redraw_running,7,
                                [{file,"/observer_cli/_build/default/deps/observer_cli/src/observer_cli.erl"},
                                 {line,132}]}]}

[erlang:process_info(X) || X <- erlang:processes()]. shows multiple entries {current_function,undefined} (which is expected due to the HiPE compilation).

rewrite network view.

Can't see useful information from Net view.

A preliminary idea:
We can't draw graph like observer.
make it more like iftop

catch io terminated exception ?

it might be related to otp 26, but can be caught at higher level, maybe.

2024-04-04T21:53:36.629647+02:00 [error] Error in process <0.4553.0> on node '[email protected]' with exit value:, {terminated,[{io,format,[<<"\e[H|\e[48;2;184;0;0mHome(H)\e[49m|\e[48;2;80;80;80mNetwork(N)\e[49m|\e[48;2;80;80;80mSystem(S)\e[49m|\e[48;2;80;80;80mEts(E)\e[49m\e[48;2;80;80;80m/Mnesia(M)\e[49m|\e[48;2;80;80;80mApp(A)\e[49m|\e[48;2;80;80;80mDoc(D)\e[49m|\e[48;2;80;80;80mPlugin(P)\e[49mrecon:proc_window(memory, 7, 1500) Interval:1500 | \e[32;1m0Days 0:1:40 \e[0m|\n|Erlang/OTP 26 [erts-14.2.1] [emqx] [64-bit] [s"...>>,[]],[{file,"io.erl"},{line,98},{error_info,#{cause => {io,terminated},module => erl_stdlib_errors}}]},{observer_cli,redraw_running,8,[{file,"observer_cli.erl"},{line,198}]}]}

Crash while rendering ETS table `Tab`

{{case_clause,undefined},
[{observer_cli_ets,get_ets_info,2,
                    [{file,"........./lib/observer_cli/src/observer_cli_ets.erl"},
                     {line,131}]},
{observer_cli_ets,'-render_ets_info/3-lc$^0/1-0-',2,
                    [{file,"........./lib/observer_cli/src/observer_cli_ets.erl"},
                     {line,75}]},
  {observer_cli_ets,'-render_ets_info/3-lc$^0/1-0-',2,
                    [{file,"........./lib/observer_cli/src/observer_cli_ets.erl"},
                     {line,77}]},
  {observer_cli_ets,render_ets_info,3,
                   [{file,"........./lib/observer_cli/src/observer_cli_ets.erl"},
                     {line,77}]},
  {observer_cli_ets,render_worker,5,
                    [{file,"........./lib/observer_cli/src/observer_cli_ets.erl"},
                     {line,63}]}]}

Manually adding dependency :recon necessary for mix

I had to add this to my Mixfile to make it work:

defp deps do
    [
      {:observer_cli, "~> 1.0.8"},
      {:recon, "~> 2.3.2"}
    ]
  end

It seems that the recon dependency is properly defined in observer_cli version 1.0.8 for mix.

Otherwise i get the following error when starting the application:

** (Mix) Could not start application recon: could not find application file: recon.app

System pane exception

Hi,

Just trying out this project and it's amazing, thank you!

I hit a bug when pressing "S" for System Info:

[error] Process #PID<10241.9605.0> on node :"[email protected]" raised an exception
** (ArgumentError) errors were found at the given arguments:

  * 1st argument: not a textual representation of an integer

    :erlang.list_to_integer('--')
    (observer_cli 1.7.2) src/observer_cli_system.erl:300: :observer_cli_system.sys_info/1
    (observer_cli 1.7.2) src/observer_cli_system.erl:213: :observer_cli_system.render_sys_info/1
    (observer_cli 1.7.2) src/observer_cli_system.erl:60: :observer_cli_system.render_worker/3 pid=<10241.9605.0>
[error] :gen_event handler Sentry.LoggerBackend installed in Logger terminating
** (stop) exited in: GenServer.call(Sentry.TaskSupervisor, {:start_task, [{:"[email protected]", Logger, #PID<0.100.0>}, [#PID<0.100.0>], {:erlang, :apply, [#Function<2.128473629/0 in Sentry.Client.do_send_event/3>, []]}], nil, nil}, :infinity)
    ** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
... extra Sentry Logger info

Context:

iex([email protected])4> System.build_info
%{
  build: "1.13.3 (compiled with Erlang/OTP 24)",
  date: "2022-04-05T13:52:29Z",
  otp_release: "24",
  revision: "",
  version: "1.13.3"
}

iex([email protected])22> System.cmd "uname", ["-a"]
{"Linux ip-10-20-33-130.eu-central-1.compute.internal 4.14.268-205.500.amzn2.x86_64 #1 SMP Wed Mar 2 18:38:38 UTC 2022 x86_64 Linux\n",
 0}

This is running on AWS Fargate and it looks like the reason is that they have a non-standard ps command, it doesn't respond to --version or --help. This failure is handled on line 291 of observer_cli_system.erl but those "--" string values aren't subsequently supported.

Unable to connect remote ejabberd server

erl -sname `monitor@localhost`
observer_cli:start('ejabberd@nikhil5', 'actualcookiedata').

On the remote machine, the ejabberd server is running with node name ejabberd@nikhil5. On the same remote machine while running above command, the process monitor tool gives the following error-

badrpc,{'EXIT',{undef,[{observer_cli,start,[1500],[]},
                    {rpc,'-handle_call_call/6-fun-0-',5,
                         [{file,"rpc.erl"},{line,197}]}]}}}

Any suggestions/ideas why this is happening? Machine runs CentOS, and ejabberd-18.01, if that information is useful.

Support Nerves by no longer depending on hard-coded OTP_VERSION file location

I tried to add observer_cli to Nerves.
However, upon attempting to start it, it will crash with the following error:

00:01:22.567 [error] Process #PID<0.1234.0> on node :"[email protected]" raised an exception
** (MatchError) no match of right hand side value: {:error, :enoent}
    (observer_cli) src/observer_cli.erl:607: :observer_cli.get_stable_system_info/0
    (observer_cli) src/observer_cli.erl:123: :observer_cli.render_worker/3

Digging into the code, it seems that observer_cli is using a function called get_stable_system_info (which seems to only be used to display the full version (both major and minor) of OTP that under the covers attempts to read a file located at e.g. /srv/erlang/releases/22/OTP_VERSION

This location does not exist on Nerves (and actually the whole 22 folder) . The OTP_VERSION file can therefore not be read.


My suggestion would be to fallback to just set Version = erlang:system_info(otp_release) in case the file is not found, rather than crashing violently.

The file:read_file(".../OTP_VERSION") call should be done in the background

This PR added a file:read_file/1 call needed for the Home page: #59

On my system, under specific circumstances, when I start observer_cli it takes 10+ seconds to show the Home page. The same problem happens when going to another page and coming back to the Home page. The Erlang node is doing a lot of file operations, and as a result the schedulers are not able to do this file:read_file/1 call in a timely manner. This is not good because this kind of scenario is precisely what I am trying to investigate.

The relevant code today is at https://github.com/zhongwencool/observer_cli/blob/master/src/observer_cli.erl#L781-L786 Removing these lines greatly improves the responsiveness of observer-cli in my case, with the downside being that the version now only shows "23".

I do not think removing the precise version is a good idea because the more accurate version is useful. However perhaps getting the more accurate version should be done in the background instead, and the value updated whenever the file:read_file/1 call has completed. Also I would suggest keeping this value cached to avoid reading the file every time the user goes back to the Home tab.

What do you think?

/cc @gerhard @mkuratczyk

Observer_cli startup crash on OTP 23

This is happening with OTP 23.1.1
=ERROR REPORT==== 21-Oct-2020::13:00:05.140642 === Error in process <9621.159.12> on node butler_server@localhost with exit value: {badarg,[{erlang,element,[2,false],[]}, {recon_alloc,container_value,4, [{file,"src/recon_alloc.erl"},{line,699}]}, {recon_alloc,container_size,3, [{file,"src/recon_alloc.erl"},{line,671}]}, {lists,map,2,[{file,"lists.erl"},{line,1243}]}, {recon_alloc,memory,2,[{file,"src/recon_alloc.erl"},{line,208}]}, {observer_cli,get_change_system_info,0, [{file,"src/observer_cli.erl"},{line,616}]}, {observer_cli,redraw_running,7, [{file,"src/observer_cli.erl"},{line,150}]}]}

Could not start observer_cli (remote node).

Remote node error

{{badmatch,
     {badrpc,
         {'EXIT',
             {undef,
                 [{observer_cli,get_stable_system_info,[local_node],[]},
                  {rpc,'-handle_call_call/6-fun-0-',5,
                      [{file,"rpc.erl"},{line,206}]}]}}}},
 [{observer_cli,refresh,12,
      [{file,
           "/Users/hezhiqiang/ElixirProjects/tools/observer_cli3/_build/default/lib/observer_cli/src/observer_cli.erl"},
       {line,286}]}]}
q
quit

Remote node could be connected, but can start the observer_cli

([email protected])8> net_kernel:connect_node('[email protected]').
true

node [email protected] started with:

rebar3 shell --name [email protected] --setcookie mycookie

The remote node should add the recon as dep ?

observer_cli crashes in OTP-26

I found the error after upgrading a project to OTP-26. I created a new rebar3 project and I got the crash pasted below. They have changed how erlang shell works so I believe it can be related :

=ERROR REPORT==== 12-Jun-2023::11:57:50.466132 ===
** State machine user_drv terminating
** Last event = {info,{#Ref<0.4201476985.4260364290.213397>,ok}}
** When server state  = {server,
                         {state,
                          {state,#Ref<0.4201476985.4260495362.213395>,
                           {<0.69.0>,#Ref<0.4201476985.4260364290.213399>},
                           {<0.68.0>,#Ref<0.4201476985.4260364290.213397>},
                           #{input => true,echo => false,tty => true,
                             canon => false},
                           true,
                           [[124,<<"\e[4m">>,<<"\e[7m">>,113,40,113,117,105,
                             116,41,32,112,40,112,97,117,115,101,41,32,114,47,
                             114,114,40,114,101,100,117,99,116,105,111,110,41,
                             32,109,47,109,109,40,109,101,109,41,98,47,98,98,
                             40,98,105,110,97,114,121,32,109,101,109,41,32,
                             116,47,116,116,40,116,111,116,97,108,32,104,101,
                             97,112,32,115,105,122,101,41,32,109,113,47,109,
                             109,113,40,109,115,103,32,113,117,101,117,101,41,
                             32,57,40,112,114,111,99,32,57,32,105,110,102,111,
                             41,32,70,47,66,40,112,97,103,101,32,102,111,114,
                             119,97,114,100,47,98,97,99,107,41,32,<<"\e[0m">>,
                             124],
                            "|42 |<0.195.0>   |    2.7422 KB |application_master:init/4             |                   43| 0        |application_master:main_loop/2   |",
                            "|41 |<0.57.0>    |    2.7656 KB |rex                                   |                   42| 0        |gen_server:loop/7                |",
                            "|40 |<0.58.0>    |    2.7852 KB |erlang:apply/2                        |                   69| 0        |rpc:nodes_observer_loop/1        |",
                            "|39 |<0.108.0>   |    2.7891 KB |dtls_listener_sup                     |                   94| 0        |gen_server:loop/7                |",
                            "|38 |<0.72.0>    |    2.8281 KB |logger_handler_watcher                |                   82| 0        |gen_server:loop/7                |",
                            "|37 |<0.75.0>    |    2.8438 KB |kernel_refc                           |                   73| 0        |gen_server:loop/7                |",
                            "|36 |<0.68.0>    |    2.8750 KB |user_drv_writer                       |                  205| 0        |prim_tty:writer_loop/2           |",
                            "|35 |<0.69.0>    |    3.0313 KB |user_drv_reader                       |                   66| 0        |prim_tty:reader_loop/6           |",
                            "|34 |<0.112.0>   |    3.7734 KB |application_master:start_it/4         |                  144| 0        |application_master:loop_it/4     |",
                            "|33 |<0.196.0>   |    3.7734 KB |application_master:start_it/4         |                  142| 0        |application_master:loop_it/4     |",
                            "|32 |<0.46.0>    |    3.8594 KB |application_master:init/4             |                   42| 0        |application_master:main_loop/2   |",
                            "|31 |<0.131.0>   |    3.8906 KB |disk_log_sup                          |                  207| 0        |gen_server:loop/7                |",
                            "|30 |<0.76.0>    |    3.8984 KB |kernel_safe_sup                       |                  365| 0        |gen_server:loop/7                |",
                            "|29 |<0.94.0>    |    3.9063 KB |ssl_pem_cache                         |                  108| 0        |gen_server:loop/7                |",
                            "|28 |<0.119.0>   |    3.9063 KB |httpc_rebar                           |                   87| 0        |gen_server:loop/7                |",
                            "|27 |<0.62.0>    |    3.9180 KB |global_group                          |                  125| 0        |gen_server:loop/7                |",
                            "|26 |<0.115.0>   |    4.6016 KB |httpc_profile_sup                     |                  529| 0        |gen_server:loop/7                |",
                            "|25 |<0.200.0>   |    5.7891 KB |erlang:apply/2                        |                 1556| 0        |io:execute_request/3             |",
                            "|24 |<0.71.0>    |    6.9141 KB |logger_sup                            |                  565| 0        |gen_server:loop/7                |",
                            "|23 |<0.47.0>    |    8.5391 KB |application_master:start_it/4         |                  552| 0        |application_master:loop_it/4     |",
                            "|22 |<0.132.0>   |    8.7109 KB |disk_log_server                       |                  300| 0        |gen_server:loop/7                |",
                            "|21 |<0.55.0>    |   10.5000 KB |inet_db                               |                  399| 0        |gen_server:loop/7                |",
                            "|20 |<0.78.0>    |   10.5156 KB |logger_std_h_default                  |                  183| 0        |gen_server:loop/7                |",
                            "|19 |<0.42.0>    |   11.6172 KB |logger                                |                  907| 0        |gen_server:loop/7                |",
                            "|18 |<0.88.0>    |   13.3125 KB |application_master:start_it/4         |                  336| 0        |application_master:loop_it/4     |",
                            "|17 |<0.65.0>    |   13.3984 KB |supervisor_bridge:user_sup/1          |                  242| 0        |gen_server:loop/7                |",
                            "|16 |<0.95.0>    |   13.4453 KB |ssl_manager                           |                  206| 0        |gen_server:loop/7                |",
                            "|15 |<0.116.0>   |   13.4453 KB |httpc_manager                         |                  186| 0        |gen_server:loop/7                |",
                            "|14 |<0.90.0>    |   13.4609 KB |logger_std_h_ssl_handler              |                  185| 0        |gen_server:loop/7                |",
                            "|13 |<0.59.0>    |   14.0664 KB |global_name_server                    |                  333| 0        |gen_server:loop/7                |",
                            "|12 |<0.0.0>     |   21.1094 KB |init                                  |                 7008| 0        |init:loop/1                      |",
                            "|11 |<0.70.0>    |   21.1328 KB |user                                  |                 1117| 0        |group:server_loop/3              |",
                            "|10 |<0.53.0>    |   21.1641 KB |file_server_2                         |                 8448| 0        |gen_server:loop/7                |",
                            "|9  |<0.66.0>    |   33.7578 KB |user_drv                              |                 6764| 0        |gen_statem:loop_receive/3        |",
                            "|8  |<0.192.0>   |   33.8047 KB |disk_log:init/2                       |                 4536| 0        |disk_log:loop/1                  |",
                            "|7  |<0.49.0>    |   41.8281 KB |kernel_sup                            |                 3469| 0        |gen_server:loop/7                |",
                            "|6  |<0.9.0>     |   84.5313 KB |rebar_agent                           |               248829| 0        |erlang:hibernate/3               |",
                            "|5  |<0.197.0>   |  278.3594 KB |erlang:apply/2                        |                20266| 0        |shell:shell_rep/5                |",
                            "|4  |<0.44.0>    |  449.4375 KB |application_controller                |                97718| 0        |gen_server:loop/7                |",
                            "|3  |<0.50.0>    |  673.3125 KB |code_server                           |               181611| 0        |code_server:loop/1               |",
                            "|2  |<0.10.0>    |    1.0635 MB |erl_prim_loader                       |              4151209| 0        |erl_prim_loader:loop/3           |",
                            [124,<<"\e[42m">>,49,32,32,124,60,48,46,49,57,49,
                             46,48,62,32,32,32,124,32,32,32,32,49,46,53,48,49,
                             52,32,77,66,32,124,103,114,111,117,112,58,115,
                             101,114,118,101,114,47,52,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,124,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,32,49,49,52,54,54,124,32,48,32,32,32,32,32,32,
                             32,32,124,103,114,111,117,112,58,109,111,114,101,
                             95,100,97,116,97,47,54,32,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,32,<<"\e[49m">>,124],
                            [124,<<"\e[7m">>,78,111,32,124,32,80,105,100,32,
                             32,32,32,32,32,32,32,<<"\e[0m">>,124,
                             <<"\e[48;2;184;0;0m">>,32,32,32,32,32,77,101,109,
                             111,114,121,32,32,32,<<"\e[0m">>,124,<<"\e[7m">>,
                             78,97,109,101,32,111,114,32,73,110,105,116,105,
                             97,108,32,67,97,108,108,32,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,32,32,32,124,<<"\e[7m">>,32,
                             32,32,32,32,32,32,32,32,32,32,82,101,100,117,99,
                             116,105,111,110,115,124,<<"\e[7m">>,32,77,115,
                             103,81,117,101,117,101,32,124,<<"\e[7m">>,67,117,
                             114,114,101,110,116,32,70,117,110,99,116,105,111,
                             110,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,32,<<"\e[0m">>,124],
                            [124,69,116,115,32,32,32,32,32,32,32,32,124,32,56,
                             52,56,46,49,48,57,52,32,75,66,32,32,124,32,48,50,
                             46,57,51,37,32,124,32,82,117,110,81,117,101,117,
                             101,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,32,32,124,32,48,32,32,32,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,32,32,32,32,124,32,71,99,32,
                             87,111,114,100,115,32,82,101,99,108,97,105,109,
                             101,100,32,32,32,124,32,56,57,48,53,54,50,51,47,
                             49,57,52,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,<<"\e[0m">>,124],
                            [124,65,116,111,109,32,32,32,32,32,32,32,124,32,
                             52,51,54,46,48,57,51,56,32,75,66,32,32,124,32,48,
                             49,46,53,49,37,32,124,32,80,111,114,116,32,80,97,
                             114,97,108,108,101,108,105,115,109,32,40,43,115,
                             112,112,41,32,32,32,124,32,102,97,108,115,101,32,
                             32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             124,32,71,99,32,67,111,117,110,116,32,32,32,32,
                             32,32,32,32,32,32,32,32,32,124,32,57,55,54,47,49,
                             32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,32,32,32,124,32,<<"\e[0m">>],
                            [124,80,114,111,99,101,115,115,32,32,32,32,124,32,
                             55,46,57,56,48,55,32,77,66,32,32,32,32,124,32,50,
                             56,46,50,55,37,32,124,32,67,111,100,101,32,32,32,
                             32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,32,32,124,32,56,46,49,57,51,52,32,77,66,32,32,
                             32,32,124,32,50,57,46,48,50,37,32,124,32,73,79,
                             32,73,110,112,117,116,32,32,32,32,32,32,32,32,32,
                             32,32,32,32,124,32,51,54,32,66,47,48,32,66,32,32,
                             32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,124,
                             32,<<"\e[0m">>],
                            [124,84,111,116,97,108,32,32,32,32,32,32,124,32,
                             50,56,46,50,51,52,50,32,77,66,32,32,32,124,32,49,
                             48,48,46,48,37,32,124,32,66,105,110,97,114,121,
                             32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,32,32,32,124,32,49,46,50,55,52,49,32,77,66,32,
                             32,32,32,124,32,48,52,46,53,49,37,32,124,32,73,
                             79,32,79,117,116,112,117,116,32,32,32,32,32,32,
                             32,32,32,32,32,32,124,32,49,51,32,66,47,48,32,66,
                             32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,124,32,<<"\e[0m">>],
                            [124,<<"\e[7m">>,77,101,109,32,84,121,112,101,32,
                             32,32,124,32,83,105,122,101,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,32,32,32,32,124,32,77,101,
                             109,32,84,121,112,101,32,32,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,32,32,124,32,83,105,122,101,
                             32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,32,124,32,73,79,47,71,67,58,40,49,53,48,48,
                             109,115,41,32,32,32,32,32,32,32,124,32,84,111,
                             116,97,108,47,73,110,99,114,101,109,101,110,116,
                             115,32,32,32,32,32,32,32,32,32,<<"\e[0m">>,124],
                            [124,<<"\e[4m">>,65,116,111,109,32,67,111,117,110,
                             116,32,124,32,49,52,52,55,55,47,49,48,52,56,53,
                             55,54,32,32,32,32,32,32,32,32,32,<<"\e[0m">>,124,
                             32,112,115,32,45,111,32,112,109,101,109,32,32,32,
                             32,32,32,32,32,32,32,32,32,32,32,32,32,124,32,48,
                             46,52,37,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,32,32,32,32,124,32,82,101,100,115,40,84,111,
                             116,97,108,47,83,105,110,99,101,76,97,115,116,32,
                             124,32,52,56,52,50,56,55,53,47,52,56,52,50,56,55,
                             53,32,32,32,32,32,32,32,32,32,32,<<"\e[0m">>,124],
                            [124,80,111,114,116,32,67,111,117,110,116,32,124,
                             32,50,47,54,53,53,51,54,32,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,<<"\e[0m">>,124,32,112,115,
                             32,45,111,32,112,99,112,117,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,32,32,124,32,51,48,46,48,37,
                             32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,124,32,67,111,110,116,101,120,116,32,83,119,
                             105,116,99,104,32,32,32,32,32,32,32,124,32,51,54,
                             51,55,48,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,<<"\e[0m">>,124],
                            [124,80,114,111,99,32,67,111,117,110,116,32,124,
                             32,49,49,54,47,50,54,50,49,52,52,32,32,32,32,32,
                             32,32,32,32,32,32,32,<<"\e[0m">>,124,32,86,101,
                             114,115,105,111,110,32,32,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,32,32,32,124,32,50,54,32,32,
                             32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,32,124,32,65,99,116,105,118,101,32,84,97,115,
                             107,32,32,32,32,32,32,32,32,32,32,124,32,50,32,
                             32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,124,32,<<"\e[0m">>],
                            [124,<<"\e[7m">>,83,121,115,116,101,109,32,32,32,
                             32,32,124,32,67,111,117,110,116,47,76,105,109,
                             105,116,32,32,32,32,32,32,32,32,32,32,32,124,32,
                             83,121,115,116,101,109,32,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,32,32,32,32,32,124,32,83,
                             116,97,116,117,115,32,32,32,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,124,32,83,116,97,116,32,73,110,
                             102,111,32,32,32,32,32,32,32,32,32,32,32,32,124,
                             32,83,105,122,101,32,32,32,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,32,32,32,32,<<"\e[0m">>,124],
                            [124,69,114,108,97,110,103,47,79,84,80,32,50,54,
                             32,91,101,114,116,115,45,49,52,46,48,93,32,91,
                             115,111,117,114,99,101,93,32,91,54,52,45,98,105,
                             116,93,32,91,115,109,112,58,56,58,56,93,32,91,
                             100,115,58,56,58,56,58,49,48,93,32,91,97,115,121,
                             110,99,45,116,104,114,101,97,100,115,58,49,93,32,
                             91,106,105,116,58,110,115,93,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             32,32,32,32,32,32,32,124,32,<<"\e[0m">>],
                            [{ansi,<<"\e[H">>},
                             124,<<"\e[48;2;184;0;0m">>,72,111,109,101,40,72,
                             41,<<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,78,
                             101,116,119,111,114,107,40,78,41,<<"\e[49m">>,
                             124,<<"\e[48;2;80;80;80m">>,83,121,115,116,101,
                             109,40,83,41,<<"\e[49m">>,124,
                             <<"\e[48;2;80;80;80m">>,69,116,115,40,69,41,
                             <<"\e[49m">>,<<"\e[48;2;80;80;80m">>,
                             <<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,65,112,
                             112,40,65,41,<<"\e[49m">>,124,
                             <<"\e[48;2;80;80;80m">>,68,111,99,40,68,41,
                             <<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,80,108,
                             117,103,105,110,40,80,41,<<"\e[49m">>,114,101,99,
                             111,110,58,112,114,111,99,95,99,111,117,110,116,
                             40,109,101,109,111,114,121,44,32,52,50,41,32,73,
                             110,116,101,114,118,97,108,58,49,53,48,48,109,
                             115,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
                             124,32,<<"\e[32;1m">>,48,68,97,121,115,32,48,58,
                             48,58,50,32,32,32,32,32,32,<<"\e[0m">>,124]],
                           [],[],[],undefined,212,56,true,<<"\e[H\e[2J">>,
                           <<"\e[A">>,<<"\n">>,<<"\b">>,<<"\e[C">>,<<"\t">>,
                           <<"\e[J">>,<<"\e[%p1%d@">>,<<"\e[%p1%dP">>,
                           <<"\e[6n">>,<<"\e\\[([0-9]+);([0-9]+)R">>,
                           {re_pattern,0,1,0,
                            <<69,82,67,80,94,1,0,0,16,8,0,0,1,0,0,0,255,255,
                              255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,64,
                              0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                              0,0,0,0,0,0,131,1,26,27,110,0,0,0,8,0,0,0,0,0,
                              0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,
                              110,0,0,0,0,8,3,0,136,0,0,0,40,0,0,0,0,0,0,0,0,
                              0,0,0,0,0,0,0,0,0,0,0,0,98,131,0,141,131,0,135,
                              146,131,0,46,146,131,0,39,29,59,110,0,0,0,0,
                              104,224,255,167,255,255,255,135,254,255,255,71,
                              0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,121,0,39,
                              119,0,80,110,0,0,0,0,0,0,255,3,254,255,255,7,
                              254,255,255,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                              107,146,131,0,39,29,59,110,0,0,0,0,104,224,255,
                              167,255,255,255,135,254,255,255,71,0,0,0,0,0,0,
                              0,0,0,0,0,0,0,0,0,0,98,121,0,39,120,0,126,29,7,
                              120,0,135,119,0,67,131,0,61,146,131,0,21,7,91,
                              0,3,7,146,131,0,9,29,59,91,0,4,7,121,0,9,120,0,
                              21,110,0,0,0,0,0,0,255,115,254,255,29,4,200,
                              127,62,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,120,
                              0,61,120,0,208,120,1,26,0>>}},
                          #Ref<0.4201476985.4260364290.213397>,
                          #Ref<0.4201476985.4260364290.213399>,new,undefined,
                          <0.70.0>,<0.191.0>,
                          {gr,2,1,<0.191.0>,
                           [{group,0,<0.70.0>,{}},
                            {group,1,<0.191.0>,{shell,start,[init]}}]},
                          {{<0.191.0>,#Ref<0.4201476985.4260364289.213224>,
                            {<0.203.0>,#Ref<0.4201476985.4260364290.215159>}},
                           {[{<0.191.0>,
                              {requests,
                               [{redraw_prompt,[],".. ",{[],{[],[]},[]}}]}}],
                            []}}}}
** Reason for termination = error:function_clause
** Callback modules = [user_drv]
** Callback mode = state_functions
** Stacktrace =
**  [{prim_tty,cols,
               [[{ansi,<<"\e[H">>},
                 124,<<"\e[48;2;184;0;0m">>,72,111,109,101,40,72,41,
                 <<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,78,101,116,119,111,
                 114,107,40,78,41,<<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,83,
                 121,115,116,101,109,40,83,41,<<"\e[49m">>,124,
                 <<"\e[48;2;80;80;80m">>,69,116,115,40,69,41,<<"\e[49m">>,
                 <<"\e[48;2;80;80;80m">>,<<"\e[49m">>,124,
                 <<"\e[48;2;80;80;80m">>,65,112,112,40,65,41,<<"\e[49m">>,124,
                 <<"\e[48;2;80;80;80m">>,68,111,99,40,68,41,<<"\e[49m">>,124,
                 <<"\e[48;2;80;80;80m">>,80,108,117,103,105,110,40,80,41,
                 <<"\e[49m">>,114,101,99,111,110,58,112,114,111,99,95,99,111,
                 117,110,116,40,109,101,109,111,114,121,44,32,52,50,41,32,73,
                 110,116,101,114,118,97,108,58,49,53,48,48,109,115,32,32,32,
                 32,32,32,32,32,32,32,32,32,32,32,32,124,32,<<"\e[32;1m">>,48,
                 68,97,121,115,32,48,58,48,58,50,32,32,32,32,32,32,
                 <<"\e[0m">>,124],
                true],
               [{file,"prim_tty.erl"},{line,935}]},
     {prim_tty,'-cols_multiline/4-lc$^0/1-0-',3,
               [{file,"prim_tty.erl"},{line,933}]},
     {prim_tty,'-cols_multiline/4-lc$^0/1-0-',3,
               [{file,"prim_tty.erl"},{line,933}]},
     {prim_tty,cols_multiline,4,[{file,"prim_tty.erl"},{line,933}]},
     {prim_tty,handle_request,2,[{file,"prim_tty.erl"},{line,628}]},
     {prim_tty,handle_request,2,[{file,"prim_tty.erl"},{line,551}]},
     {user_drv,io_request,2,[{file,"user_drv.erl"},{line,781}]},
     {user_drv,io_requests,2,[{file,"user_drv.erl"},{line,834}]}]

Failed to write log message to stdout, trying stderr
=CRASH REPORT==== 12-Jun-2023::11:57:50.468069 ===
  crasher:
    initial call: user_drv:init/1
    pid: <0.66.0>
    registered_name: user_drv
    exception error: no function clause matching
                     prim_tty:cols([{ansi,<<"\e[H">>},
                                    124,<<"\e[48;2;184;0;0m">>,72,111,109,101,
                                    40,72,41,<<"\e[49m">>,124,
                                    <<"\e[48;2;80;80;80m">>,78,101,116,119,
                                    111,114,107,40,78,41,<<"\e[49m">>,124,
                                    <<"\e[48;2;80;80;80m">>,83,121,115,116,
                                    101,109,40,83,41,<<"\e[49m">>,124,
                                    <<"\e[48;2;80;80;80m">>,69,116,115,40,69,
                                    41,<<"\e[49m">>,<<"\e[48;2;80;80;80m">>,
                                    <<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,
                                    65,112,112,40,65,41,<<"\e[49m">>,124,
                                    <<"\e[48;2;80;80;80m">>,68,111,99,40,68,
                                    41,<<"\e[49m">>,124,
                                    <<"\e[48;2;80;80;80m">>,80,108,117,103,
                                    105,110,40,80,41,<<"\e[49m">>,114,101,99,
                                    111,110,58,112,114,111,99,95,99,111,117,
                                    110,116,40,109,101,109,111,114,121,44,32,
                                    52,50,41,32,73,110,116,101,114,118,97,108,
                                    58,49,53,48,48,109,115,32,32,32,32,32,32,
                                    32,32,32,32,32,32,32,32,32,124,32,
                                    <<"\e[32;1m">>,48,68,97,121,115,32,48,58,
                                    48,58,50,32,32,32,32,32,32,<<"\e[0m">>,
                                    124],
                                   true) (prim_tty.erl, line 935)
      in function  prim_tty:'-cols_multiline/4-lc$^0/1-0-'/3 (prim_tty.erl, line 933)
      in call from prim_tty:'-cols_multiline/4-lc$^0/1-0-'/3 (prim_tty.erl, line 933)
      in call from prim_tty:cols_multiline/4 (prim_tty.erl, line 933)
      in call from prim_tty:handle_request/2 (prim_tty.erl, line 628)
      in call from prim_tty:handle_request/2 (prim_tty.erl, line 551)
      in call from user_drv:io_request/2 (user_drv.erl, line 781)
      in call from user_drv:io_requests/2 (user_drv.erl, line 834)
    ancestors: [<0.70.0>,<0.65.0>,kernel_sup,<0.47.0>]
    message_queue_len: 0
    messages: []
    links: [<0.69.0>,<0.70.0>,<0.191.0>,<0.68.0>]
    dictionary: [{current_group,<0.191.0>}]
    trap_exit: true
    status: running
    heap_size: 75113
    stack_size: 28
    reductions: 245182
  neighbours:
    neighbour:
      pid: <0.68.0>
      registered_name: user_drv_writer
      initial call: prim_tty:writer/1
      current_function: {prim_tty,writer_loop,2}
      ancestors: [user_drv,<0.65.0>,kernel_sup,<0.47.0>]
      message_queue_len: 0
      links: [<0.66.0>]
      trap_exit: false
      status: waiting
      heap_size: 233
      stack_size: 8
      reductions: 231
      current_stacktrace: [{prim_tty,writer_loop,2,[{file,"prim_tty.erl"},{line,518}]},
                  {proc_lib,init_p_do_apply,3,
                            [{file,"proc_lib.erl"},{line,241}]}]
    neighbour:
      pid: <0.69.0>
      registered_name: user_drv_reader
      initial call: prim_tty:reader/1
      current_function: {prim_tty,reader_loop,6}
      ancestors: [user_drv,<0.65.0>,kernel_sup,<0.47.0>]
      message_queue_len: 0
      links: [<0.66.0>]
      trap_exit: false
      status: waiting
      heap_size: 233
      stack_size: 13
      reductions: 71
      current_stacktrace: [{prim_tty,reader_loop,6,[{file,"prim_tty.erl"},{line,444}]},
                  {proc_lib,init_p_do_apply,3,
                            [{file,"proc_lib.erl"},{line,241}]}]
Failed to write log message to stdout, trying stderr
=SUPERVISOR REPORT==== 12-Jun-2023::11:57:50.471432 ===
    supervisor: {<0.65.0>,user_sup}
    errorContext: child_terminated
    reason: {function_clause,
                [{prim_tty,cols,
                     [[{ansi,<<"\e[H">>},
                       124,<<"\e[48;2;184;0;0m">>,72,111,109,101,40,72,41,
                       <<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,78,101,116,
                       119,111,114,107,40,78,41,<<"\e[49m">>,124,
                       <<"\e[48;2;80;80;80m">>,83,121,115,116,101,109,40,83,
                       41,<<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,69,116,115,
                       40,69,41,<<"\e[49m">>,<<"\e[48;2;80;80;80m">>,
                       <<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,65,112,112,40,
                       65,41,<<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,68,111,
                       99,40,68,41,<<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,
                       80,108,117,103,105,110,40,80,41,<<"\e[49m">>,114,101,
                       99,111,110,58,112,114,111,99,95,99,111,117,110,116,40,
                       109,101,109,111,114,121,44,32,52,50,41,32,73,110,116,
                       101,114,118,97,108,58,49,53,48,48,109,115,32,32,32,32,
                       32,32,32,32,32,32,32,32,32,32,32,124,32,<<"\e[32;1m">>,
                       48,68,97,121,115,32,48,58,48,58,50,32,32,32,32,32,32,
                       <<"\e[0m">>,124],
                      true],
                     [{file,"prim_tty.erl"},{line,935}]},
                 {prim_tty,'-cols_multiline/4-lc$^0/1-0-',3,
                     [{file,"prim_tty.erl"},{line,933}]},
                 {prim_tty,'-cols_multiline/4-lc$^0/1-0-',3,
                     [{file,"prim_tty.erl"},{line,933}]},
                 {prim_tty,cols_multiline,4,
                     [{file,"prim_tty.erl"},{line,933}]},
                 {prim_tty,handle_request,2,
                     [{file,"prim_tty.erl"},{line,628}]},
                 {prim_tty,handle_request,2,
                     [{file,"prim_tty.erl"},{line,551}]},
                 {user_drv,io_request,2,[{file,"user_drv.erl"},{line,781}]},
                 {user_drv,io_requests,2,[{file,"user_drv.erl"},{line,834}]}]}
    offender: [{pid,<0.70.0>},{mod,user_sup}]

Failed to write log message to stdout, trying stderr
=ERROR REPORT==== 12-Jun-2023::11:57:50.472163 ===
** Generic server <0.65.0> terminating
** Last message in was {'EXIT',<0.70.0>,
                           {function_clause,
                               [{prim_tty,cols,
                                    [[{ansi,<<"\e[H">>},
                                      124,<<"\e[48;2;184;0;0m">>,72,111,109,
                                      101,40,72,41,<<"\e[49m">>,124,
                                      <<"\e[48;2;80;80;80m">>,78,101,116,119,
                                      111,114,107,40,78,41,<<"\e[49m">>,124,
                                      <<"\e[48;2;80;80;80m">>,83,121,115,116,
                                      101,109,40,83,41,<<"\e[49m">>,124,
                                      <<"\e[48;2;80;80;80m">>,69,116,115,40,
                                      69,41,<<"\e[49m">>,
                                      <<"\e[48;2;80;80;80m">>,<<"\e[49m">>,
                                      124,<<"\e[48;2;80;80;80m">>,65,112,112,
                                      40,65,41,<<"\e[49m">>,124,
                                      <<"\e[48;2;80;80;80m">>,68,111,99,40,68,
                                      41,<<"\e[49m">>,124,
                                      <<"\e[48;2;80;80;80m">>,80,108,117,103,
                                      105,110,40,80,41,<<"\e[49m">>,114,101,
                                      99,111,110,58,112,114,111,99,95,99,111,
                                      117,110,116,40,109,101,109,111,114,121,
                                      44,32,52,50,41,32,73,110,116,101,114,
                                      118,97,108,58,49,53,48,48,109,115,32,32,
                                      32,32,32,32,32,32,32,32,32,32,32,32,32,
                                      124,32,<<"\e[32;1m">>,48,68,97,121,115,
                                      32,48,58,48,58,50,32,32,32,32,32,32,
                                      <<"\e[0m">>,124],
                                     true],
                                    [{file,"prim_tty.erl"},{line,935}]},
                                {prim_tty,'-cols_multiline/4-lc$^0/1-0-',3,
                                    [{file,"prim_tty.erl"},{line,933}]},
                                {prim_tty,'-cols_multiline/4-lc$^0/1-0-',3,
                                    [{file,"prim_tty.erl"},{line,933}]},
                                {prim_tty,cols_multiline,4,
                                    [{file,"prim_tty.erl"},{line,933}]},
                                {prim_tty,handle_request,2,
                                    [{file,"prim_tty.erl"},{line,628}]},
                                {prim_tty,handle_request,2,
                                    [{file,"prim_tty.erl"},{line,551}]},
                                {user_drv,io_request,2,
                                    [{file,"user_drv.erl"},{line,781}]},
                                {user_drv,io_requests,2,
                                    [{file,"user_drv.erl"},{line,834}]}]}}
** When Server state == {state,user_sup,undefined,<0.70.0>,
                               {<0.65.0>,user_sup}}
** Reason for termination ==
** {function_clause,[{prim_tty,cols,
                               [[{ansi,<<"\e[H">>},
                                 124,<<"\e[48;2;184;0;0m">>,72,111,109,101,40,
                                 72,41,<<"\e[49m">>,124,
                                 <<"\e[48;2;80;80;80m">>,78,101,116,119,111,
                                 114,107,40,78,41,<<"\e[49m">>,124,
                                 <<"\e[48;2;80;80;80m">>,83,121,115,116,101,
                                 109,40,83,41,<<"\e[49m">>,124,
                                 <<"\e[48;2;80;80;80m">>,69,116,115,40,69,41,
                                 <<"\e[49m">>,<<"\e[48;2;80;80;80m">>,
                                 <<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,65,
                                 112,112,40,65,41,<<"\e[49m">>,124,
                                 <<"\e[48;2;80;80;80m">>,68,111,99,40,68,41,
                                 <<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,80,
                                 108,117,103,105,110,40,80,41,<<"\e[49m">>,
                                 114,101,99,111,110,58,112,114,111,99,95,99,
                                 111,117,110,116,40,109,101,109,111,114,121,
                                 44,32,52,50,41,32,73,110,116,101,114,118,97,
                                 108,58,49,53,48,48,109,115,32,32,32,32,32,32,
                                 32,32,32,32,32,32,32,32,32,124,32,
                                 <<"\e[32;1m">>,48,68,97,121,115,32,48,58,48,
                                 58,50,32,32,32,32,32,32,<<"\e[0m">>,124],
                                true],
                               [{file,"prim_tty.erl"},{line,935}]},
                     {prim_tty,'-cols_multiline/4-lc$^0/1-0-',3,
                               [{file,"prim_tty.erl"},{line,933}]},
                     {prim_tty,'-cols_multiline/4-lc$^0/1-0-',3,
                               [{file,"prim_tty.erl"},{line,933}]},
                     {prim_tty,cols_multiline,4,
                               [{file,"prim_tty.erl"},{line,933}]},
                     {prim_tty,handle_request,2,
                               [{file,"prim_tty.erl"},{line,628}]},
                     {prim_tty,handle_request,2,
                               [{file,"prim_tty.erl"},{line,551}]},
                     {user_drv,io_request,2,
                               [{file,"user_drv.erl"},{line,781}]},
                     {user_drv,io_requests,2,
                               [{file,"user_drv.erl"},{line,834}]}]}

Failed to write log message to stdout, trying stderr
=CRASH REPORT==== 12-Jun-2023::11:57:50.472719 ===
  crasher:
    initial call: supervisor_bridge:user_sup/1
    pid: <0.65.0>
    registered_name: []
    exception exit: {function_clause,
                        [{prim_tty,cols,
                             [[{ansi,<<"\e[H">>},
                               124,<<"\e[48;2;184;0;0m">>,72,111,109,101,40,
                               72,41,<<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,
                               78,101,116,119,111,114,107,40,78,41,
                               <<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,83,
                               121,115,116,101,109,40,83,41,<<"\e[49m">>,124,
                               <<"\e[48;2;80;80;80m">>,69,116,115,40,69,41,
                               <<"\e[49m">>,<<"\e[48;2;80;80;80m">>,
                               <<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,65,
                               112,112,40,65,41,<<"\e[49m">>,124,
                               <<"\e[48;2;80;80;80m">>,68,111,99,40,68,41,
                               <<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,80,
                               108,117,103,105,110,40,80,41,<<"\e[49m">>,114,
                               101,99,111,110,58,112,114,111,99,95,99,111,117,
                               110,116,40,109,101,109,111,114,121,44,32,52,50,
                               41,32,73,110,116,101,114,118,97,108,58,49,53,
                               48,48,109,115,32,32,32,32,32,32,32,32,32,32,32,
                               32,32,32,32,124,32,<<"\e[32;1m">>,48,68,97,121,
                               115,32,48,58,48,58,50,32,32,32,32,32,32,
                               <<"\e[0m">>,124],
                              true],
                             [{file,"prim_tty.erl"},{line,935}]},
                         {prim_tty,'-cols_multiline/4-lc$^0/1-0-',3,
                             [{file,"prim_tty.erl"},{line,933}]},
                         {prim_tty,'-cols_multiline/4-lc$^0/1-0-',3,
                             [{file,"prim_tty.erl"},{line,933}]},
                         {prim_tty,cols_multiline,4,
                             [{file,"prim_tty.erl"},{line,933}]},
                         {prim_tty,handle_request,2,
                             [{file,"prim_tty.erl"},{line,628}]},
                         {prim_tty,handle_request,2,
                             [{file,"prim_tty.erl"},{line,551}]},
                         {user_drv,io_request,2,
                             [{file,"user_drv.erl"},{line,781}]},
                         {user_drv,io_requests,2,
                             [{file,"user_drv.erl"},{line,834}]}]}
      in function  gen_server:handle_common_reply/8 (gen_server.erl, line 1208)
    ancestors: [kernel_sup,<0.47.0>]
    message_queue_len: 0
    messages: []
    links: [<0.49.0>]
    dictionary: []
    trap_exit: true
    status: running
    heap_size: 2586
    stack_size: 28
    reductions: 49495
  neighbours:

Failed to write log message to stdout, trying stderr
=SUPERVISOR REPORT==== 12-Jun-2023::11:57:50.473356 ===
    supervisor: {local,kernel_sup}
    errorContext: child_terminated
    reason: {function_clause,
                [{prim_tty,cols,
                     [[{ansi,<<"\e[H">>},
                       124,<<"\e[48;2;184;0;0m">>,72,111,109,101,40,72,41,
                       <<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,78,101,116,
                       119,111,114,107,40,78,41,<<"\e[49m">>,124,
                       <<"\e[48;2;80;80;80m">>,83,121,115,116,101,109,40,83,
                       41,<<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,69,116,115,
                       40,69,41,<<"\e[49m">>,<<"\e[48;2;80;80;80m">>,
                       <<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,65,112,112,40,
                       65,41,<<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,68,111,
                       99,40,68,41,<<"\e[49m">>,124,<<"\e[48;2;80;80;80m">>,
                       80,108,117,103,105,110,40,80,41,<<"\e[49m">>,114,101,
                       99,111,110,58,112,114,111,99,95,99,111,117,110,116,40,
                       109,101,109,111,114,121,44,32,52,50,41,32,73,110,116,
                       101,114,118,97,108,58,49,53,48,48,109,115,32,32,32,32,
                       32,32,32,32,32,32,32,32,32,32,32,124,32,<<"\e[32;1m">>,
                       48,68,97,121,115,32,48,58,48,58,50,32,32,32,32,32,32,
                       <<"\e[0m">>,124],
                      true],
                     [{file,"prim_tty.erl"},{line,935}]},
                 {prim_tty,'-cols_multiline/4-lc$^0/1-0-',3,
                     [{file,"prim_tty.erl"},{line,933}]},
                 {prim_tty,'-cols_multiline/4-lc$^0/1-0-',3,
                     [{file,"prim_tty.erl"},{line,933}]},
                 {prim_tty,cols_multiline,4,
                     [{file,"prim_tty.erl"},{line,933}]},
                 {prim_tty,handle_request,2,
                     [{file,"prim_tty.erl"},{line,628}]},
                 {prim_tty,handle_request,2,
                     [{file,"prim_tty.erl"},{line,551}]},
                 {user_drv,io_request,2,[{file,"user_drv.erl"},{line,781}]},
                 {user_drv,io_requests,2,[{file,"user_drv.erl"},{line,834}]}]}
    offender: [{pid,<0.65.0>},
               {id,user},
               {mfargs,{user_sup,start,[]}},
               {restart_type,temporary},
               {significant,false},
               {shutdown,2000},
               {child_type,supervisor}]

Thank you :)

Jump to process by pid

If I know the pid of a process, is there any way for me to jump directly to it? Without having to search through the list? I was thinking entering something like <#.#.#> and hitting enter?

(btw, we find this project super useful, thanks!)

在以mq排序来查看进程列表时发现存在一个进程有两条消息

环境

observer_cli version: 1.4.0
otp version: 19.3.5.4 - erts-8.3.5.4

重现方式:

erl -pa $(rebar3 path)

1> observer_cli:start().
> mq
|No | Pid        | MsgQueue  |Name or Initial Call                 |      Memory | Reductions          |Current Function                  |
|1  |<0.75.0>    |2          |erlang:apply/2                       |    7.2266 KB| 684                 |io:execute_request/2              |

消息为:

|Home(H)|Process Info(P)|Messages(M)|Dictionary(D)|Current Stack(C)|State(S)|Interval: 1500ms                     | 0Days 0:1:31     |
<0.75.0> Message Len:2
[{'EXIT',<0.79.0>,stop},{'EXIT',<0.80.0>,stop}]
|q(quit)

进程堆栈

|Home(H)|Process Info(P)|Messages(M)|Dictionary(D)|Current Stack(C)|State(S)|Interval: 1500ms                     | 0Days 0:2:28     |
erlang:process_info(<0.75.0>, current_stacktrace).      
|io:execute_request/2                                               | io.erl:572                                                     | 
|observer_cli_process:parse_cmd/2                                   | /home/pwf/work/fg_server/hunter/_build/default/lib/observer_cl | 
|observer_cli_process:manager/2                                     | /home/pwf/work/fg_server/hunter/_build/default/lib/observer_cl | 
|erl_eval:do_apply/6                                                | erl_eval.erl:674                                               | 
|shell:exprs/7                                                      | shell.erl:686                                                  | 
|shell:eval_exprs/7                                                 | shell.erl:641                                                  | 
|shell:eval_loop/3                                                  | shell.erl:626                                                  |
|q(quit) 

猜测

怀疑是 observer_cli 开启的进程没有处理exit消息

Bad arithmetic error

I get this when I sort by mq. I haven't dug into why it occurs yet. I have not seen it on any other sort options.

15:16:55.374 [error] Error in process #PID<6859.16834.4700> on node :"[email protected]" with exit value:
{:badarith,
 [{:observer_cli_lib, :byte_to_str, 1,
   [file: '/app/deps/observer_cli/src/observer_cli_lib.erl', line: 100]},
  {:observer_cli, :"-render_process_rank/4-fun-4-", 4,
   [file: '/app/deps/observer_cli/src/observer_cli.erl', line: 349]},
  {:lists, :foldr, 3, [file: 'lists.erl', line: 1276]},
  {:observer_cli, :render_process_rank, 4,
   [file: '/app/deps/observer_cli/src/observer_cli.erl', line: 341]},
  {:observer_cli, :redraw, 6,
   [file: '/app/deps/observer_cli/src/observer_cli.erl', line: 112]}]}

Plugin per row shortcut

I would like to have my plugin be able to set a shortcut for each row in the sheet, similar to how we can choose processes in the Home view. In my case I could select a RabbitMQ queue I want to get more information about. It would be good if I could also link this detailed queue view to its detailed process view.

What do you think?

Row numbers in plugins?

Is it possible to add row numbers in plugins, switching to a detail view when a row is selected?
Thank you!

add into rebar, but seems can't work, thanks in advance~

==============add in my rebar:
Deps = [
{observer_cli, ".", {git, "https://github.com/zhongwencool/observer_cli.git", {tag,"1.0.4"}}},
{lager, ".
"},

===============error report as following:
Dependency not available: observer_cli-.* ({git,
"https://github.com/zhongwencool/observer_cli.git",
{tag,"1.0.4"}})
ERROR: compile failed while processing /home/ejab/svn_code/ejabberd-matrix/dev-3.0: rebar_abort
make: *** [src] Error 1

solved, need to run rebar get_deps before compile~

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.