Giter Site home page Giter Site logo

phoenixframework / phoenix_live_dashboard Goto Github PK

View Code? Open in Web Editor NEW
1.9K 43.0 178.0 3.92 MB

Realtime dashboard with metrics, request logging, plus storage, OS and VM insights

License: MIT License

Elixir 76.79% JavaScript 8.82% HTML 1.47% SCSS 12.92%
phoenix liveview dashboard metrics ecto

phoenix_live_dashboard's Introduction

Phoenix LiveDashboard

CI

Online Documentation.

LiveDashboard provides real-time performance monitoring and debugging tools for Phoenix developers. It provides the following modules:

  • Home - See general information about the system

  • OS Data - See general information about OS, such as CPU, Memory and Disk usage

  • Metrics - See how your application performs under different conditions by visualizing :telemetry events with real-time charts

  • Request logging - See everything that was logged for certain requests

  • Applications - See, filter, and search applications in the current node and view their processes in a supervision tree

  • Processes - See, filter, and search processes in the current node

  • Ports - See, filter, and search ports (responsible for I/O) in the current node

  • Sockets - See, filter, and search sockets (responsible for tcp/udp) in the current node

  • ETS - See, filter, and search ETS tables (in-memory storage) in the current node

  • Ecto Stats - Shows index, table, and general usage about the underlying Ecto Repo storage

The dashboard also works across nodes. If your nodes are connected via Distributed Erlang, then you can access information from node B while accessing the dashboard on node A.

screenshot

Installation

To start using LiveDashboard, you will need three steps:

  1. Add the phoenix_live_dashboard dependency
  2. Configure LiveView
  3. Add dashboard access

1. Add the phoenix_live_dashboard dependency

Add the following to your mix.exs and run mix deps.get:

def deps do
  [
    {:phoenix_live_dashboard, "~> 0.7"}
  ]
end

2. Configure LiveView

The LiveDashboard is built on top of LiveView. If LiveView is already installed in your app, feel free to skip this section.

If you plan to use LiveView in your application in the future, we recommend you to follow the official installation instructions. This guide only covers the minimum steps necessary for the LiveDashboard itself to run.

First, update your endpoint's configuration to include a signing salt. You can generate a signing salt by running mix phx.gen.secret 32 (note Phoenix v1.5+ apps already have this configuration):

# config/config.exs
config :my_app, MyAppWeb.Endpoint,
  live_view: [signing_salt: "SECRET_SALT"]

Then add the Phoenix.LiveView.Socket declaration to your endpoint:

socket "/live", Phoenix.LiveView.Socket

And you are good to go!

3. Add dashboard access for development-only usage

Once installed, update your router's configuration to forward requests to a LiveDashboard with a unique name of your choosing:

# lib/my_app_web/router.ex
use MyAppWeb, :router
import Phoenix.LiveDashboard.Router

...

if Mix.env() == :dev do
  scope "/" do
    pipe_through :browser
    live_dashboard "/dashboard"
  end
end

This is all. Run mix phx.server and access the "/dashboard" to configure the necessary modules.

Extra: Add dashboard access on all environments (including production)

If you want to use the LiveDashboard in production, you should put it behind some authentication and allow only admins to access it. If your application does not have an admins-only section yet, you can use Plug.BasicAuth to set up some basic authentication as long as you are also using SSL (which you should anyway):

# lib/my_app_web/router.ex
use MyAppWeb, :router
import Phoenix.LiveDashboard.Router

...

pipeline :admins_only do
  plug :admin_basic_auth
end

scope "/" do
  pipe_through [:browser, :admins_only]
  live_dashboard "/dashboard"
end

defp admin_basic_auth(conn, _opts) do
  username = System.fetch_env!("AUTH_USERNAME")
  password = System.fetch_env!("AUTH_PASSWORD")
  Plug.BasicAuth.basic_auth(conn, username: username, password: password)
end

If you are running your application behind a proxy or a webserver, you also have to make sure they are configured for allowing WebSocket upgrades. For example, here is an article on how to configure Nginx with Phoenix and WebSockets.

Finally, you will also want to configure your config/prod.exs and use your domain name under the check_origin configuration:

check_origin: ["//myapp.com"]

Then you should be good to go!

Using from the command line with PLDS

It's possible to use the LiveDashboard without having to add it as a dependency of your application, or when you don't have Phoenix installed. PLDS is a command line tool that provides a standalone version of LiveDashboard with some batteries included.

You can install it with:

$ mix escript.install hex plds

And connect to a running node with:

$ plds server --connect mynode --open

For more details, please check the PLDS documentation.

Contributing

For those planning to contribute to this project, you can run a dev version of the dashboard with the following commands:

$ mix setup
$ mix dev

Additionally, you may pass some options to enable Ecto testing. For example, to enable the PostgreSQL repo:

$ mix dev --postgres

...and to enable the MySQL repo:

$ mix dev --mysql

...and to enable the SQLite repo:

$ mix dev --sqlite

Alternatively, run iex -S mix dev [flags] if you also want a shell.

Before submitting a pull request, discard any changes that were made to the dist directory.

For example, to rollback using git restore:

$ git restore dist

License

MIT License. Copyright (c) 2019 Michael Crumm, Chris McCord, José Valim.

phoenix_live_dashboard's People

Contributors

alexcastano avatar archdragon avatar cblavier avatar cheerfulstoic avatar chrismccord avatar davydog187 avatar dependabot[bot] avatar dkuku avatar fidr avatar fuelen avatar josevalim avatar kianmeng avatar lostkobrakai avatar maennchen avatar mcrumm avatar moogle19 avatar orsinium avatar paulostazeski avatar pawurb avatar petrus-jvrensburg avatar philss avatar romankotov avatar romkor avatar rupurt avatar sabiwara avatar sax avatar sksar avatar supersimple avatar timothyvanderaerden avatar wojtekmach 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  avatar  avatar  avatar  avatar

phoenix_live_dashboard's Issues

Style menu for small layouts

Now that we have added a new element to the menu, things break down a bit:

Screenshot 2020-03-20 at 15 37 56

However, if this is too complicate to fix, we can leave it as is for now. /cc @archdragon

Dashboard does not respect Endpoint url path configuration when redirecting after initial page load

Hello! I believe I have found a bug related to nested paths, similar to #64

I have a Phoenix application that serves requests behind an edge router. The edge router strips path prefixes when routing to services. For example, requests made to http://my-router.com/my-phoenix-app/foo/bar are routed to the Phoenix path /foo/bar.

To account for this, I added the stripped path prefix back in when generating Phoenix URLs by configuring our application's Endpoint like so:

config :my_phoenix_app, MyPhoenixApp.Endpoint, url: [path: "/my-phoenix-app"]

Following the installation guides, I have this snippet added to my Router:

live_dashboard("/dashboard")

When I navigate to http://my-router.com/my-phoenix-app/dashboard I see the dashboard as expected, and the web-socket connection established. However, the dashboard is unable to redirect from http://my-router.com/my-phoenix-app/foo/bar/dashboard to http://my-router.com/my-phoenix-app/foo/bar/dashboard/nonode%40nohost and raises the following error:

** (ArgumentError) cannot invoke handle_params nor live_redirect/live_link to "http://my-router.com/my-phoenix-app/foo/bar/dashboard/nonode%40nohost" because it isn't defined in MyPhoenixApp.Router

I was able to work around this issue by adding an additional route including the stripped path prefix, but this feels sub-optimal:

live_dashboard("/dashboard")
live_dashboard("/my-phoenix-app/dashboard")

I'm not sure if this is the expected behavior or a bug in Phoenix Live Dashboard or Phoenix Live View. If it is a bug, I am happy to help fix it with a bit of guidance. Thanks!

Clicking between your app, Phoenix, VM and other tabs resets each tab's stats

If you want to monitor the metrics of your application, chances are you would want to cycle between viewing your app's tab, Phoenix's tab and the VM's tab without having each tab get 100% wiped out in between switching tabs.

Could an option be introduced to persist the stats for the lifetime of the socket? This way we can jump between each metric, home and processes without losing the state on each page transition.

Otherwise it looks like you'll need to open 5 browser tabs to watch each thing individually without losing the previous stats.

Add support for distribution metric

EDIT: I never bothered to add a description here because I assumed I would handle the implementation. That was clearly a mistake so I am adding a description now.

My plan for the implementation had been to use a bar chart, like the uPlot "latency histogram" demo:

Screen Shot 2021-04-28 at 7 50 16 PM

Except that demo didn't exist when I made this issue, so now we have a huge head start :)

In the initial implementation, the buckets will be user-defined: values are given in reporter_options as described in the distribution/2 docs:

# lib/my_app_web/telemetry.ex
distribution("phoenix.router_dispatch.stop.duration",
  unit: {:native, :millisecond},
  reporter_options: [
    buckets: [200, 500, 1000]
  ]
)

...which would create a bar chart with four buckets:

  • -Inf – 200
  • 200 – 500
  • 500 – 1000
  • 1000 – +Inf

The trickier part is how to handle multi-series data, but we can solve that in a separate issue.

Style tables

I have added a process table, now we only need to style it before we add more tables. :)

Screenshot 2020-03-20 at 15 36 08

/cc @archdragon

Responsive chart styles

Howdy 👋

Great work so far gents! Have you put any thought into how or if you'll handle multiple screen sizes? Ideally I'd love the dashboard to be responsive to screen size so I can fully utilize my 27" screen. Something along these lines

  • iPad Pro & smaller: Stack charts in a single column
  • <= 1900px: Current 2 col layout
  • <= 2400px: 3 col layout
  • > 2400px: 4 col layout

IEx tab ?

I created a proof of concept of iex - I use Code.string_eval currently but probably can be hooked up to real iex session. What are you thinking about something like that - Its useful but may be a security risk
image

Make chart assigns temporary

The chart dataset assign(s) should be temporary assigns so we don't hold them in memory after we send them down

Long port paths break the layout

image

we should either wrap in the column which is probably going to be ugly, or trim the path (and display the full path on hover) like this:

image

wdyt?

Bake in tooltip support

I would like to add some tooltips that explains some of the terms in the dashboard. The idea is that we would have a question mark that, on mouse over, shows extra information.

For example, for "Run queues" we could explain what the "Run queues" are. Below is a screenshot of what I have in mind, with the tooltip locations drawn in red (although in practice they won't be red and they will be smaller). There are four of them, one for run queues and one for each limit:

Screenshot 2020-03-19 at 01 24 01

@archdragon I would appreciate if you could provide a template for these things, for now you can use "Lorem Ipsum" as the default and I will fill them in later. ❤️

key :menu not found in: %Phoenix.LiveView.Socket.AssignsNotInSocket{}

When following the README to add the dashboard to an existing Phoenix app I get the following error:

[error] #PID<0.4802.0> running TestyWeb.Endpoint (connection #PID<0.4794.0>, stream id 3) terminated
Server: localhost:4000 (http)
Request: GET /dashboard/nonode%40nohost
** (exit) an exception was raised:
    ** (KeyError) key :menu not found in: %Phoenix.LiveView.Socket.AssignsNotInSocket{}
        (phoenix_live_dashboard 0.1.0) lib/phoenix/live_dashboard/live/menu_live.ex:66: Phoenix.LiveDashboard.MenuLive.maybe_active_live_redirect/4
        (phoenix_live_dashboard 0.1.0) lib/phoenix/live_dashboard/live/menu_live.ex:23: anonymous fn/2 in Phoenix.LiveDashboard.MenuLive.render/1
        (phoenix_live_view 0.10.0) lib/phoenix_live_view/diff.ex:221: Phoenix.LiveView.Diff.traverse/5
        (phoenix_live_view 0.10.0) lib/phoenix_live_view/diff.ex:92: Phoenix.LiveView.Diff.render/3
        (phoenix_live_view 0.10.0) lib/phoenix_live_view/static.ex:274: Phoenix.LiveView.Static.to_rendered_content_tag/4
        (phoenix_live_dashboard 0.1.0) lib/phoenix/live_dashboard/templates/layout/live.html.leex:7: anonymous fn/2 in Phoenix.LiveDashboard.LayoutView."live.html"/1
        (phoenix_live_view 0.10.0) lib/phoenix_live_view/diff.ex:221: Phoenix.LiveView.Diff.traverse/5
        (phoenix_live_view 0.10.0) lib/phoenix_live_view/diff.ex:92: Phoenix.LiveView.Diff.render/3
        (phoenix_live_view 0.10.0) lib/phoenix_live_view/static.ex:274: Phoenix.LiveView.Static.to_rendered_content_tag/4
        (phoenix_live_view 0.10.0) lib/phoenix_live_view/static.ex:137: Phoenix.LiveView.Static.render/3
        (phoenix_live_view 0.10.0) lib/phoenix_live_view/controller.ex:35: Phoenix.LiveView.Controller.live_render/3
        (phoenix 1.4.16) lib/phoenix/router.ex:288: Phoenix.Router.__call__/2
        (testy 0.1.0) lib/testy_web/endpoint.ex:1: TestyWeb.Endpoint.plug_builder_call/2
        (testy 0.1.0) lib/plug/debugger.ex:132: TestyWeb.Endpoint."call (overridable 3)"/2
        (testy 0.1.0) lib/testy_web/endpoint.ex:1: TestyWeb.Endpoint.call/2
        (phoenix 1.4.16) lib/phoenix/endpoint/cowboy2_handler.ex:42: Phoenix.Endpoint.Cowboy2Handler.init/4
        (cowboy 2.7.0) /Users/me/Projects/testy/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2
        (cowboy 2.7.0) /Users/me/Projects/testy/deps/cowboy/src/cowboy_stream_h.erl:320: :cowboy_stream_h.execute/3
        (cowboy 2.7.0) /Users/me/Projects/testy/deps/cowboy/src/cowboy_stream_h.erl:302: :cowboy_stream_h.request_process/3
        (stdlib 3.12) proc_lib.erl:249: :proc_lib.init_p_do_apply/3

Adding something like Map.has_key?(socket.assigns, :menu) && to the if statements in lines 66 and 76 in lib/phoenix/live_dashboard/live/menu_live.ex helped.

Add screenshots

Readme in dire need for screenshots. You know, +200 popularity for peanuts

LiveDashboard compilation issue with SouctAPM eex templating

The app blows up while compiling for prod, here is the error:

 == Compilation error in file lib/phoenix/live_dashboard/layout_view.ex ==
 ** (UndefinedFunctionError) function ScoutApm.Instruments.EExEngine.compile/2 is undefined (module ScoutApm.Instruments.EExEngine is not available)
     ScoutApm.Instruments.EExEngine.compile("lib/phoenix/live_dashboard/templates/layout/dash.html.eex", "dash.html")
     (phoenix 1.4.16) lib/phoenix/template.ex:355: Phoenix.Template.compile/3
     (phoenix 1.4.16) lib/phoenix/template.ex:166: anonymous fn/4 in Phoenix.Template."MACRO-__before_compile__"/2
     (elixir 1.10.2) lib/enum.ex:2111: Enum."-reduce/3-lists^foldl/2-0-"/3
     (phoenix 1.4.16) expanding macro: Phoenix.Template.__before_compile__/1
     lib/phoenix/live_dashboard/layout_view.ex:1: Phoenix.LiveDashboard.LayoutView (module)

relevant scout config in config.exs

config :phoenix, :template_engines,
  eex: ScoutApm.Instruments.EExEngine,
  exs: ScoutApm.Instruments.ExsEngine

app deps

  defp deps do
    [
      {:phoenix, "~> 1.4.11"},
      {:phoenix_pubsub, "~> 1.1"},
      {:phoenix_ecto, "~> 4.0"},
      {:ecto_sql, "~> 3.1"},
      {:postgrex, ">= 0.0.0"},
      {:phoenix_html, "~> 2.11"},
      {:phoenix_live_reload, "~> 1.2", only: :dev},
      {:gettext, "~> 0.11"},
      {:jason, "~> 1.0"},
      {:plug_cowboy, "~> 2.0"},
      {:csv, "~> 2.3"},
      {:phoenix_live_view, "~> 0.12.0"},
      {:sentry, "~> 7.0"},
      {:scout_apm, "~> 1.0.6"},
      {:credo, "~> 1.3", only: [:dev, :test], runtime: false},
      {:phoenix_live_dashboard, "~> 0.1"}
    ]
  end

Unable to mount the live socket at a nested path

I've got an app that is only accessible on a specific path of my url (in my case, /app). I need to have the js client connect it's socket to /app/live instead of /live. It looks like that is hard-coded here:
https://github.com/phoenixframework/phoenix_live_dashboard/blob/master/lib/phoenix/live_dashboard/templates/layout/dash.html.eex#L2

I'd love to contribute if this is a desired feature but I'm pretty new to elixir/phoenix so I'd need to be pointed in the right direction. I'm not sure which of these is the right way to accomplish this:

  • read live_socket_path from assigns (how does a developer pass that value in?)
  • read live_socket_path from config (do we use an existing config or something new?)
  • something else?

Prune charts data

So someone reported that keeping the "Metrics" tab open after a long period of time ended-up consuming 5GB of memory. This makes sense, given that we keep pushing data to charts forever and ever. I am wondering if we should put an upper limit on the number of elements on the chart and start pruning old data once we go past N elements, for example, N = 10000.

Hi @leeoniya, if you don't mind, do you have any insights on what we can do here?

Counter events not updating charts

Environment

  • Elixir version (elixir -v): Elixir 1.10.2 (compiled with Erlang/OTP 21)
  • Phoenix version (mix deps): 1.5.1
  • Phoenix LiveView version (mix deps): 0.12.0
  • Phoenix Dashboard version (mix deps): 0.2.1
  • Operating system: OSX
  • Browsers you attempted to reproduce this bug on (the more the merrier): Chrome

Actual behavior

When creating a counter like counter("my_app.new_registration.count", tags: [:user_type]) and referencing a measurement that does not exist (like :count in this instance), the extract_measurement/2 function returns nil, which is falsey and the event doesn't update the charts
https://github.com/akoutmos/phoenix_live_dashboard/blob/master/lib/phoenix/live_dashboard/telemetry_listener.ex#L23

Expected behavior

According to the docs on counters, the measurement that is selected should be ignored by the reporter as it is not used (https://hexdocs.pm/telemetry_metrics/Telemetry.Metrics.html#counter/2). As such, ending your event name with a key that does not exist in the measurements map should still increment the counter.

At first glance it seems like it may just be as simple as adding the following prior to the existing function:

defp extract_measurement(%Telemetry.Metrics.Counter{} = _metric, _measurement), do: 1

Huge thanks for effort put into LiveDashboard...I have really been enjoying using it and adding it to my apps :). It is tools like this that make the Elixir developer experience top notch 👍

Allow opt-in for showing env vars

The idea is to allow users to opt-in to displaying some env vars on the dashboard homepage. For example, when running on Gigalixir, it might be helpful to see the "SOURCE_VERSION" in the dashboard. AppSignal uses the var "APP_REVISION" to similar effect.

Selected env vars could be configured for display on the live_dashboard route, like so:

live_dashboard "/dashboard",
  metrics: MyAppWeb.Telemetry,
  environment: ["SOURCE_VERSION", "MY_ENV_VAR"]

Note: LiveDashboard would not define any "magic" env vars for any purpose -- the user can choose which of their env vars they would like to see displayed.

OsMonLive FunctionClauseError on Windows

Environment

  • Elixir version (elixir -v): Erlang/OTP 22 [erts-10.5] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1]
    Elixir 1.9.4 (compiled with Erlang/OTP 20)
  • Phoenix version (mix deps): 1.5.1
  • Phoenix LiveView version (mix deps): 0.12.1
  • Phoenix Dashboard version (mix deps): 0.2.1
  • Operating system: Windows 10 / powershell 5.1
  • Browsers you attempted to reproduce this bug on (the more the merrier): Firefox 75.0 (probably not a browser issue though)

Actual behavior

The request fails with FunctionClauseError: no function clause matching in Phoenix.LiveDashboard.OSMonLive.calculate_cpu_total/2 (see phoenix error page screenshot for details)

image

It seems that on Windows :os_mon does not support cpu metrics

Description

The operating system monitor, OS_Mon, provides the following services:

  • cpu_sup CPU load and utilization supervision (Unix)

I confirmed this by manually trying to start the os_mon application on windows

iex(3)> :os_mon.start(nil, nil)
{:ok, #PID<0.106.0>}

iex(4)> :cpu_sup.util([:detailed, :per_cpu])

18:36:06.605 [warn]  OS_MON (:cpu_sup) called by #PID<0.102.0>, not started

{:all, 0, 0, []}

Expected behavior

The page should not break on Windows and should probably report inability to gather cpu stats

JS error when opening metrics

Hi there,

I included Phoenix Live Dashboard in an existing application. It works fine, except the metrics, they throw JS errors:

Uncaught TypeError: Cannot read property '2' of undefined
    at VM23 cforum%40quirm:496
    at Array.map (<anonymous>)
    at Object.values (VM23 cforum%40quirm:496)
    at VM23 cforum%40quirm:496
    at Array.forEach (<anonymous>)
    at Dt (VM23 cforum%40quirm:496)
    at jt (VM23 cforum%40quirm:496)
    at Yt (VM23 cforum%40quirm:496)
    at dt (VM23 cforum%40quirm:496)
    at Object.ft [as setData] (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at e.updated (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at VM23 cforum%40quirm:496
    at VM23 cforum%40quirm:496
    at Array.forEach (<anonymous>)
    at e.value (VM23 cforum%40quirm:496)
    at VM23 cforum%40quirm:496
    at Array.forEach (<anonymous>)
    at e.value (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at VM23 cforum%40quirm:496
    at Set.forEach (<anonymous>)
    at VM23 cforum%40quirm:496
    at e.value (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at VM23 cforum%40quirm:496
    at VM23 cforum%40quirm:496
    at Object.callback (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at VM23 cforum%40quirm:496
    at e.decode (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at WebSocket.conn.conn.onmessage (VM23 cforum%40quirm:496)
Uncaught TypeError: Cannot read property '2' of undefined
    at VM23 cforum%40quirm:496
    at Array.map (<anonymous>)
    at Object.values (VM23 cforum%40quirm:496)
    at VM23 cforum%40quirm:496
    at Array.forEach (<anonymous>)
    at Dt (VM23 cforum%40quirm:496)
    at jt (VM23 cforum%40quirm:496)
    at Yt (VM23 cforum%40quirm:496)
    at dt (VM23 cforum%40quirm:496)
    at Object.ft [as setData] (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at e.updated (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at VM23 cforum%40quirm:496
    at VM23 cforum%40quirm:496
    at Array.forEach (<anonymous>)
    at e.value (VM23 cforum%40quirm:496)
    at VM23 cforum%40quirm:496
    at Array.forEach (<anonymous>)
    at e.value (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at VM23 cforum%40quirm:496
    at Set.forEach (<anonymous>)
    at VM23 cforum%40quirm:496
    at e.value (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at VM23 cforum%40quirm:496
    at VM23 cforum%40quirm:496
    at Object.callback (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at VM23 cforum%40quirm:496
    at e.decode (VM23 cforum%40quirm:496)
    at e.value (VM23 cforum%40quirm:496)
    at WebSocket.conn.conn.onmessage (VM23 cforum%40quirm:496)

Did I do something wrong?

Allow hook for metrics to be populated with historical data before or after components first renders

I started a discussion here but I think it deserves an issue of its own to discuss the appropriate API and desired requirements, and to gauge other users interest.

I’d like the ability when opening the dashboard in production to have some buffered data displayed there immediately. In my use case I’d like it to come from a circular buffer but @josevalim made it clear that though he’s open to a hook for this, no actual buffering will occur within live_dashboard itself, so the source could just as easily be Redis or a database query. I think the value would be substantial (and I’d like to make an example integration perhaps with a generator in the project to help guide users interested in this) since it will give some context when opening the dashboard of already in the middle of some kind of event to perhaps see patterns of activity preceding that event, but it’s hard to predict and of course it won’t meet everyone’s use case and probably can’t and shouldn’t display more than 30-90 minutes of data in practice, though I doubt that should be enforced or concerned with here. The first question I think is whether the hook is initiated client or server side, and whether announced via a telemetry execute event or a channel broadcast or some other mechanism I’m not thinking of.

summary "http.request.stop.duration" dont really work

Environment

  • Elixir version (elixir -v): Elixir 1.10.2
  • Phoenix version (mix deps):phoenix 1.5.1
  • Phoenix LiveView version (mix deps):phoenix_live_view 0.12.1
  • Phoenix Dashboard version (mix deps):phoenix_live_dashboard 0.2.1
  • Operating system: Ubuntu
  • Browsers you attempted to reproduce this bug on (the more the merrier):

image

HTTP stats are not coming up.

      summary("http.request.stop.duration", unit: {:native, :millisecond}),
      summary("http.request.post.duration", unit: {:native, :millisecond}),
      summary("http.request.get.duration", unit: {:native, :millisecond}),

Suggestion - Allow to override/customize templates

It would be useful to have a way to add own pages, I have some Ideas like calling ps aux and displaying the data on a page but its not something we want to have upstream probably.
also customizing the app.css name in the config - this way it can be branded like the rest of the app

Inaccurate Used Memory on Linux

Environment

  • Elixir version (elixir -v): Erlang/OTP 22, Elixir 1.10.2 (compiled with Erlang/OTP 21)
  • Phoenix version (mix deps): 1.5.1
  • Phoenix LiveView version (mix deps): 0.12.1
  • Phoenix Dashboard version (mix deps): 0.2.1
  • Operating system: Linux
  • Browsers you attempted to reproduce this bug on (the more the merrier): N/A

Actual behavior

Dashboard reports memory at ~97%, 14.8/15.5GB.

Expected behavior

Only about 9 GB are in use. Linux has very aggressive caching, so it's a bit tricky to meter actual ram use ("memory pressure").

  @memory_usage_sections [
    {"Used", :minus, :free_memory, :system_total_memory,
     "The amount of memory used from the available memory"},
  ]

According to memsup docs, I think Linux free memory should be free_memory + cached_memory + buffered_memory?

Error getting started

Using phoenix 1.4.15 & phoenix_live_view 0.9.0 I get the following error when visiting the live dashboard link:

function :"Elixir.false.Phoenix.LiveDashboard.HomeLive".__live__/0 is undefined (module :"Elixir.false.Phoenix.LiveDashboard.HomeLive" is not available)

Session error

at acess the route "/dashboard" I receive a error message by session nil

Setup CI on Windows

Now that we are using OS Mon, we should probably setup the CI to run on Windows too.

Constant redirection between nodes

Installed LiveDashboard on our staging app and when I go to the dashboard URL the browser just constantly redirects between the two nodes running the app. It will pull up the initial screen and the pointer will be set to spinning. It will then go through 20 or so redirects before refreshing the page and trying all over again. Anyone else seen this behavior?

Elixir 1.10.2
Phoenix 1.4.16
Dashboard 0.1.1
Chrome 81

Getting 403 on websocket connections

Environment

  • Elixir version (elixir -v): 1.10.2
  • Phoenix version (mix deps): 1.5.0
  • Phoenix LiveView version (mix deps): 0.12.1
  • Phoenix Dashboard version (mix deps): 0.2.0
  • Operating system: Debian GNU/Linux 9.12
  • Browsers you attempted to reproduce this bug on (the more the merrier): Firefox 75, Chrome 81

Actual behavior

We have upgraded our app to use the latest Phoenix and setup Phoenix LiveView. Our staging environment runs on Racher and the Phoenix app sits behind haproxy. The web socket for LiveView connects to the server but when we navigate to the LiveDashboard the websocket gets a 403 and the page just retries over and over.

Expected behavior

I would expect the WS to connect using the same method as the main WS. We use guardian for our auth. It is very strange behavior. Anyone else experiencing this?

Adding Telemetry to router.ex is not working

Environment

  • Elixir version (elixir -v):
elixir -v
Erlang/OTP 22 [erts-10.6.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Elixir 1.10.0 (compiled with Erlang/OTP 22)
  • Phoenix version (mix deps):
mix deps
* exldap 0.6.3 (Hex package) (mix)
  locked at 0.6.3 (exldap) 412fafab
  ok
* parse_trans 3.3.0 (Hex package) (rebar3)
  locked at 3.3.0 (parse_trans) 17ef63ab
  ok
* elixir_uuid 1.2.1 (Hex package) (mix)
  locked at 1.2.1 (elixir_uuid) f7eba2ea
  ok
* mimerl 1.2.0 (Hex package) (rebar3)
  locked at 1.2.0 (mimerl) f2785856
  ok
* connection 1.0.4 (Hex package) (mix)
  locked at 1.0.4 (connection) 4a0850c9
  ok
* nimble_parsec 0.5.3 (Hex package) (mix)
  locked at 0.5.3 (nimble_parsec) 589b5af5
  ok
* makeup 1.0.1 (Hex package) (mix)
  locked at 1.0.1 (makeup) 49736fe5
  ok
* metrics 1.0.1 (Hex package) (rebar3)
  locked at 1.0.1 (metrics) 69b09add
  ok
* bunt 0.2.0 (Hex package) (mix)
  locked at 0.2.0 (bunt) 7af5c7e0
  ok
* unicode_util_compat 0.4.1 (Hex package) (rebar3)
  locked at 0.4.1 (unicode_util_compat) 1d1848c4
  ok
* idna 6.0.0 (Hex package) (rebar3)
  locked at 6.0.0 (idna) 4bdd305e
  ok
* gettext 0.17.4 (Hex package) (mix)
  locked at 0.17.4 (gettext) 3c75b5ea
  ok
* jose 1.10.1 (Hex package) (mix)
  locked at 1.10.1 (jose) 3c7ddc8a
  ok
* ranch 1.3.2 (Hex package) (rebar3)
  locked at 1.3.2 (ranch) 6e56493a
  ok
* poolboy 1.5.2 (Hex package) (rebar3)
  locked at 1.5.2 (poolboy) dad79704
  ok
* telemetry 0.4.1 (Hex package) (rebar3)
  locked at 0.4.1 (telemetry) 4738382e
  ok
* telemetry_poller 0.5.0 (Hex package) (rebar3)
  locked at 0.5.0 (telemetry_poller) 69e4e8e6
  ok
* telemetry_metrics 0.4.2 (Hex package) (mix)
  locked at 0.4.2 (telemetry_metrics) e56ffed2
  ok
* decimal 1.8.1 (Hex package) (mix)
  locked at 1.8.1 (decimal) 3cb154b0
  ok
* jason 1.2.0 (Hex package) (mix)
  locked at 1.2.0 (jason) 116747db
  ok
* poison 3.1.0 (Hex package) (mix)
  locked at 3.1.0 (poison) fec8660e
  ok
* json_web_token 0.2.10 (Hex package) (mix)
  locked at 0.2.10 (json_web_token) 020c62f3
  ok
* ssl_verify_fun 1.1.5 (Hex package) (mix)
  locked at 1.1.5 (ssl_verify_fun) 13104d78
  ok
* paddle 0.1.4 (Hex package) (mix)
  locked at 0.1.4 (paddle) fc719a9e
  ok
* elixir_make 0.6.0 (Hex package) (mix)
  locked at 0.6.0 (elixir_make) d522695b
  ok
* bcrypt_elixir 1.1.1 (Hex package) (mix)
  locked at 1.1.1 (bcrypt_elixir) 10f658be
  ok
* comeonin 4.1.2 (Hex package) (mix)
  locked at 4.1.2 (comeonin) d8700a0c
  ok
* certifi 2.5.1 (Hex package) (rebar3)
  locked at 2.5.1 (certifi) 805abd97
  ok
* hackney 1.15.2 (Hex package) (rebar3)
  locked at 1.15.2 (hackney) e0100f8e
  ok
* earmark 1.4.3 (Hex package) (mix)
  locked at 1.4.3 (earmark) 8cf8a291
  ok
* db_connection 2.2.1 (Hex package) (mix)
  locked at 2.2.1 (db_connection) 2b02ece6
  ok
* httpoison 1.6.2 (Hex package) (mix)
  locked at 1.6.2 (httpoison) aa2c74bd
  ok
* credo 1.1.5 (Hex package) (mix)
  locked at 1.1.5 (credo) d0bbd322
  ok
* ecto 3.3.4 (Hex package) (mix)
  locked at 3.3.4 (ecto) 9b96cbb8
  ok
* ex_json_schema 0.7.3 (Hex package) (mix)
  locked at 0.7.3 (ex_json_schema) d5389c44
  ok
* makeup_elixir 0.14.0 (Hex package) (mix)
  locked at 0.14.0 (makeup_elixir) d4b316c7
  ok
* ex_doc 0.21.3 (Hex package) (mix)
  locked at 0.21.3 (ex_doc) 0db1ee8d
  ok
* phoenix_pubsub 2.0.0 (Hex package) (mix)
  locked at 2.0.0 (phoenix_pubsub) c52d948c
  ok
* cowlib 1.0.2 (Hex package) (rebar3)
  locked at 1.0.2 (cowlib) db622da0
  ok
* cowboy 1.1.2 (Hex package) (rebar3)
  locked at 1.1.2 (cowboy) f4763bbe
  ok
* mime 1.3.1 (Hex package) (mix)
  locked at 1.3.1 (mime) 6cbe761d
  ok
* artificery 0.4.2 (Hex package) (mix)
  locked at 0.4.2 (artificery) 514586f4
  ok
* distillery 2.1.1 (Hex package) (mix)
  locked at 2.1.1 (distillery) bbc7008b
  ok
* edeliver 1.8.0 (Hex package) (mix)
  locked at 1.8.0 (edeliver) 02ef9bed
  ok
* myxql 0.3.4 (Hex package) (mix)
  locked at 0.3.4 (myxql) fc8d49ba
  ok
* ecto_sql 3.3.4 (Hex package) (mix)
  locked at 3.3.4 (ecto_sql) 5eccbdbf
  ok
* plug_crypto 1.1.2 (Hex package) (mix)
  locked at 1.1.2 (plug_crypto) 6b8b608f
  ok
* plug 1.10.0 (Hex package) (mix)
  locked at 1.10.0 (plug) 422a9727
  ok
* plug_cowboy 1.0.0 (Hex package) (mix)
  locked at 1.0.0 (plug_cowboy) 01d20142
  ok
* guardian 2.1.1 (Hex package) (mix)
  locked at 2.1.1 (guardian) 189b87ba
  ok
* phoenix_swagger 0.8.2 (Hex package) (mix)
  locked at 0.8.2 (phoenix_swagger) e6d17776
  ok
* cors_plug 1.5.2 (Hex package) (mix)
  locked at 1.5.2 (cors_plug) 9af027d2
  ok
* phoenix_html 2.14.1 (Hex package) (mix)
  locked at 2.14.1 (phoenix_html) 536d5200
  ok
* phoenix 1.5.1 (Hex package) (mix)
  locked at 1.5.1 (phoenix) fc272b38
  ok
* phoenix_live_view 0.12.1 (Hex package) (mix)
  locked at 0.12.1 (phoenix_live_view) 585321e9
  ok
* phoenix_live_dashboard 0.2.0 (Hex package) (mix)
  locked at 0.2.0 (phoenix_live_dashboard) 439628ca
  ok
* phoenix_ecto 3.5.0 (Hex package) (mix)
  locked at 3.5.0 (phoenix_ecto) b9602822
  ok
  • Operating system:
uname -a
Darwin  18.7.0 Darwin Kernel Version 18.7.0: Thu Jan 23 06:52:12 PST 2020; root:xnu-4903.278.25~1/RELEASE_X86_64 x86_64
  • Browsers you attempted to reproduce this bug on (the more the merrier):
    Brave Browser

Actual behavior

When we add the following lines in router.ex we get a error

  scope "/" do
    pipe_through [:browser, :admins_only]
    live_dashboard("/dashboard"), metrics: JunctionApiWeb.Telemetry
  end

ERROR:

unexpectedly reached end of line. The current expression is invalid or incomplete
    (elixir 1.10.0) lib/kernel/parallel_compiler.ex:233: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7

Expected behavior

Expected behavior would be running the telemetry events

Broken links to hexdocs.pm/phoenix/telemetry.html in guides/metrics.md

There are two broken links in the documentation. They both lead to https://hexdocs.pm/phoenix/telemetry.html.

  1. https://github.com/phoenixframework/phoenix_live_dashboard/blame/ba7c9899742f43542166473df25a101fc86b754e/guides/metrics.md#L116
  2. https://github.com/phoenixframework/phoenix_live_dashboard/blame/ba7c9899742f43542166473df25a101fc86b754e/guides/metrics.md#L119

I tried to figure out where those links were supposed to lead. There is no telemetry.md anywhere in https://github.com/phoenixframework/phoenix/tree/master/guides, but there used to be in this project, removed in #68.

Show active alarms

Erlang ships with support for alarms in the SASL application. We could show any active alarm directly from the dashboard topbar and allow the user to dismiss it. Here is the Erlang API: http://erlang.org/doc/man/alarm_handler.html

We would need some UI for it first. :) Probably the a bell, like we see on github on the top right, which shows a counter of active alarms for us to interact with.

(ArgumentError) assign @menu not available in eex template

I get the following error on application startup:

[info] CONNECTED TO Phoenix.LiveView.Socket in 2ms
  Transport: :websocket
  Serializer: Phoenix.Socket.V2.JSONSerializer
  Parameters: %{"_csrf_token" => "REDACTED", "vsn" => "2.0.0"}
[error] GenServer #PID<0.723.0> terminating
** (ArgumentError) assign @menu not available in eex template.

Please make sure all proper assigns have been set. If this
is a child template, ensure assigns are given explicitly by
the parent template as they are not automatically forwarded.

Available assigns: [:flash, :inner_content, :live_action, :live_module, :socket]

My app has been API-only prior to adding LiveDashboard, so maybe I'm missing some standard pieces for it? Everything does seem to be working regardless of this error.

** (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

Environment

  • Elixir version (elixir -v): Elixir 1.10.2
  • Phoenix version (mix deps): 1.5.1
  • Phoenix LiveView version (mix deps): 0.12.1
  • Phoenix Dashboard version (mix deps): 0.2.0
  • Operating system: Ubuntu
  • Browsers you attempted to reproduce this bug on (the more the merrier):

I followed this full procedure to add metrics.

https://hexdocs.pm/phoenix_live_dashboard/metrics.html#installing-metrics

also added it as Children

defmodule EvercamMedia do
  use Application
  require Logger
  import EvercamMedia.Util, only: [load_storage_servers: 1]

  # See http://elixir-lang.org/docs/stable/elixir/Application.html
  # for more information on OTP Applications
  def start(_type, _args) do
    import Supervisor.Spec, warn: false

    children = [
      EvercamMediaWeb.Telemetry,
      {Phoenix.PubSub, name: EvercamMedia.PubSub}
    ]

    :ets.new(:storage_servers, [:set, :public, :named_table])
    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
    # for other strategies and supported options
    load_storage_servers([])
    opts = [strategy: :one_for_one, name: EvercamMedia.Supervisor]
    Supervisor.start_link(children, opts)
  end

  # Tell Phoenix to update the endpoint configuration
  # whenever the application is updated.
  def config_change(changed, _new, removed) do
    EvercamMediaWeb.Endpoint.config_change(changed, removed)
    :ok
  end
end

I got this error

[info] [swarm on nonode@nohost] [tracker:cluster_wait] no connected nodes, proceeding without sync
[info] GET /dashboard/nonode%40nohost/metrics/evercam_media
[debug] Processing with Phoenix.LiveView.Plug.metrics/2
  Parameters: %{"group" => "evercam_media", "node" => "nonode@nohost"}
  Pipelines: [:browser]
[info] Sent 200 in 287ms
[info] CONNECTED TO Phoenix.LiveView.Socket in 401µs
  Transport: :websocket
  Serializer: Phoenix.Socket.V2.JSONSerializer
  Parameters: %{"_csrf_token" => "AltfYy8QDGdqcXsVOSBLXwAENDg9Mign4902jgJ1Y68baE3iVCgvDzlb", "vsn" => "2.0.0"}
[error] GenServer #PID<0.2860.0> terminating
** (stop) exited in: GenServer.call({Phoenix.LiveDashboard.DynamicSupervisor, :nonode@nohost}, {:start_child, {{Phoenix.LiveDashboard.TelemetryListener, :start_link, [{#PID<0.2860.0>, [%Telemetry.Metrics.Summary{description: nil, event_name: [:evercam_media, :repo, :query], measurement: #Function<2.111777250/1 in Telemetry.Metrics.maybe_convert_measurement/2>, name: [:evercam_media, :repo, :query, :total_time], reporter_options: [], tag_values: #Function<0.111777250/1 in Telemetry.Metrics.default_metric_options/0>, tags: [], unit: :millisecond}, %Telemetry.Metrics.Summary{description: nil, event_name: [:evercam_media, :repo, :query], measurement: #Function<2.111777250/1 in Telemetry.Metrics.maybe_convert_measurement/2>, name: [:evercam_media, :repo, :query, :decode_time], reporter_options: [], tag_values: #Function<0.111777250/1 in Telemetry.Metrics.default_metric_options/0>, tags: [], unit: :millisecond}, %Telemetry.Metrics.Summary{description: nil, event_name: [:evercam_media, :repo, :query], measurement: #Function<2.111777250/1 in Telemetry.Metrics.maybe_convert_measurement/2>, name: [:evercam_media, :repo, :query, :query_time], reporter_options: [], tag_values: #Function<0.111777250/1 in Telemetry.Metrics.default_metric_options/0>, tags: [], unit: :millisecond}, %Telemetry.Metrics.Summary{description: nil, event_name: [:evercam_media, :repo, :query], measurement: #Function<2.111777250/1 in Telemetry.Metrics.maybe_convert_measurement/2>, name: [:evercam_media, :repo, :query, :queue_time], reporter_options: [], tag_values: #Function<0.111777250/1 in Telemetry.Metrics.default_metric_options/0>, tags: [], unit: :millisecond}, %Telemetry.Metrics.Summary{description: nil, event_name: [:evercam_media, :repo, :query], measurement: #Function<2.111777250/1 in Telemetry.Metrics.maybe_convert_measurement/2>, name: [:evercam_media, :repo, :query, :idle_time], reporter_options: [], tag_values: #Function<0.111777250/1 in Telemetry.Metrics.default_metric_options/0>, tags: [], unit: :millisecond}]}]}, :temporary, 5000, :worker, [Phoenix.LiveDashboard.TelemetryListener]}}, :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
    (elixir 1.10.2) lib/gen_server.ex:1013: GenServer.call/3
    lib/phoenix/live_dashboard/live/metrics_live.ex:25: Phoenix.LiveDashboard.MetricsLive.mount/3
    lib/phoenix_live_view/utils.ex:234: Phoenix.LiveView.Utils.maybe_call_mount!/3
    lib/phoenix_live_view/channel.ex:623: Phoenix.LiveView.Channel.verified_mount/4
    lib/phoenix_live_view/channel.ex:34: Phoenix.LiveView.Channel.handle_info/2
    (stdlib 3.9) gen_server.erl:637: :gen_server.try_dispatch/4
    (stdlib 3.9) gen_server.erl:711: :gen_server.handle_msg/6
    (stdlib 3.9) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: {:mount, Phoenix.LiveView.Channel}
State: {%{"joins" => 0, "params" => %{"_csrf_token" => "AltfYy8QDGdqcXsVOSBLXwAENDg9Mign4902jgJ1Y68baE3iVCgvDzlb"}, "session" => "SFMyNTY.g2gDaAJhBHQAAAAHZAACaWRtAAAAFHBoeC1GZ2xvU0ZuOFdHYmxTd01oZAAKcGFyZW50X3BpZGQAA25pbGQACHJvb3RfcGlkZAADbmlsZAAJcm9vdF92aWV3ZAAoRWxpeGlyLlBob2VuaXguTGl2ZURhc2hib2FyZC5NZXRyaWNzTGl2ZWQABnJvdXRlcmQAHUVsaXhpci5FdmVyY2FtTWVkaWFXZWIuUm91dGVyZAAHc2Vzc2lvbnQAAAACbQAAAAdtZXRyaWNzaAJkACBFbGl4aXIuRXZlcmNhbU1lZGlhV2ViLlRlbGVtZXRyeWQAB21ldHJpY3NtAAAADnJlcXVlc3RfbG9nZ2VyZAADbmlsZAAEdmlld2QAKEVsaXhpci5QaG9lbml4LkxpdmVEYXNoYm9hcmQuTWV0cmljc0xpdmVuBgDaFhy3cQFiAAFRgA.a6DPDGPuRadCPJq80vqkCGLc8z3ug-9ZFLQYdkx-hhw", "static" => "SFMyNTY.g2gDaAJhBHQAAAADZAAKYXNzaWduX25ld2pkAAVmbGFzaHQAAAAAZAACaWRtAAAAFHBoeC1GZ2xvU0ZuOFdHYmxTd01obgYA6hYct3EBYgABUYA.9VUIHRNsswTLz6_vnqoV3WJLn-HHXKGnH2IzCbmVt6o", "url" => "http://localhost:4000/dashboard/nonode%40nohost/metrics/evercam_media"}, {#PID<0.2857.0>, #Reference<0.3442257689.696254467.90101>}, %Phoenix.Socket{assigns: %{}, channel: Phoenix.LiveView.Channel, channel_pid: nil, endpoint: EvercamMediaWeb.Endpoint, handler: Phoenix.LiveView.Socket, id: nil, join_ref: "4", joined: false, private: %{session: %{}}, pubsub_server: EvercamMedia.PubSub, ref: nil, serializer: Phoenix.Socket.V2.JSONSerializer, topic: "lv:phx-FgloSFn8WGblSwMh", transport: :websocket, transport_pid: #PID<0.2857.0>}}
[error] exited in: GenServer.call({Phoenix.LiveDashboard.DynamicSupervisor, :nonode@nohost}, {:start_child, {{Phoenix.LiveDashboard.TelemetryListener, :start_link, [{#PID<0.2860.0>, [%Telemetry.Metrics.Summary{description: nil, event_name: [:evercam_media, :repo, :query], measurement: #Function<2.111777250/1 in Telemetry.Metrics.maybe_convert_measurement/2>, name: [:evercam_media, :repo, :query, :total_time], reporter_options: [], tag_values: #Function<0.111777250/1 in Telemetry.Metrics.default_metric_options/0>, tags: [], unit: :millisecond}, %Telemetry.Metrics.Summary{description: nil, event_name: [:evercam_media, :repo, :query], measurement: #Function<2.111777250/1 in Telemetry.Metrics.maybe_convert_measurement/2>, name: [:evercam_media, :repo, :query, :decode_time], reporter_options: [], tag_values: #Function<0.111777250/1 in Telemetry.Metrics.default_metric_options/0>, tags: [], unit: :millisecond}, %Telemetry.Metrics.Summary{description: nil, event_name: [:evercam_media, :repo, :query], measurement: #Function<2.111777250/1 in Telemetry.Metrics.maybe_convert_measurement/2>, name: [:evercam_media, :repo, :query, :query_time], reporter_options: [], tag_values: #Function<0.111777250/1 in Telemetry.Metrics.default_metric_options/0>, tags: [], unit: :millisecond}, %Telemetry.Metrics.Summary{description: nil, event_name: [:evercam_media, :repo, :query], measurement: #Function<2.111777250/1 in Telemetry.Metrics.maybe_convert_measurement/2>, name: [:evercam_media, :repo, :query, :queue_time], reporter_options: [], tag_values: #Function<0.111777250/1 in Telemetry.Metrics.default_metric_options/0>, tags: [], unit: :millisecond}, %Telemetry.Metrics.Summary{description: nil, event_name: [:evercam_media, :repo, :query], measurement: #Function<2.111777250/1 in Telemetry.Metrics.maybe_convert_measurement/2>, name: [:evercam_media, :repo, :query, :idle_time], reporter_options: [], tag_values: #Function<0.111777250/1 in Telemetry.Metrics.default_metric_options/0>, tags: [], unit: :millisecond}]}]}, :temporary, 5000, :worker, [Phoenix.LiveDashboard.TelemetryListener]}}, :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

Better styling for chart legend

I added some simple styling just to keep the legend from "jumping around" too much on hover, but I'll leave the real styling to the professionals. :)

Check out the clip in the description for #40 to see what I mean.

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.