diff --git a/client/js/sample.html b/client/js/sample.html deleted file mode 100644 index 41af4ed1..00000000 --- a/client/js/sample.html +++ /dev/null @@ -1,320 +0,0 @@ - - - - - zio-metrics - - - -
-
ZMX ScalaJS client
- - - - - - - - - - - - - - - - -
NameLabelsCurrent
countAll1215Add counter diagram for countAll
- - - - - - - - - - - - - - - - - - - - - - - -
NameLabelsCurrent
setGauge61.3878935514583Add gauge diagram for setGauge
adjustGauge13.895732516512574Add gauge diagram for adjustGauge
- - - - - - - - - - - - - - - - - - - - -
NameLabelsBucketsCountSum
zmxHistogram1224314675.970875502997Add histogram diagram for zmxHistogram
- - - - - - - - - - - - - - - - - - - - - - -
NameLabelsQuantilesErrorCountSum
mySummary30.0324371126Add summary diagram for mySummary
- - - - - - - - - - - - - - - - - - - - -
NameLabelsSetTagKeysCount
mySettoken10243Add set diagram for mySet
-
-
-

Diagrams

- -
-

A diagram for countAll

- -
1625867039387 -- CounterChange(Counter(countAll,Chunk()),973,1) -
-
1625867044375 -- CounterChange(Counter(countAll,Chunk()),998,1) -
-
1625867049371 -- CounterChange(Counter(countAll,Chunk()),1023,1) -
-
1625867054375 -- CounterChange(Counter(countAll,Chunk()),1048,1) -
-
1625867059431 -- CounterChange(Counter(countAll,Chunk()),1073,1) -
-
1625867064432 -- CounterChange(Counter(countAll,Chunk()),1098,1) -
-
1625867069385 -- CounterChange(Counter(countAll,Chunk()),1123,1) -
-
1625867073616 -- CounterChange(Counter(countAll,Chunk()),1145,1) -
-
1625867079388 -- CounterChange(Counter(countAll,Chunk()),1173,1) -
-
1625867084486 -- CounterChange(Counter(countAll,Chunk()),1198,1) -
-
-
-

A diagram for setGauge

- -
1625867039384 -- - GaugeChange(Gauge(setGauge,Chunk()),8.560751691871559,7.835433424265725)
-
1625867044365 -- - GaugeChange(Gauge(setGauge,Chunk()),1.8841813838269328,-93.15623353645654)
-
1625867049370 -- - GaugeChange(Gauge(setGauge,Chunk()),78.10561174094559,30.356616724172156)
-
1625867054374 -- - GaugeChange(Gauge(setGauge,Chunk()),69.9302597109951,26.973805010347384)
-
1625867059373 -- - GaugeChange(Gauge(setGauge,Chunk()),34.96599590299866,31.702806402696236)
-
1625867064380 -- - GaugeChange(Gauge(setGauge,Chunk()),41.013622630611394,3.518731978436101)
-
1625867069377 -- - GaugeChange(Gauge(setGauge,Chunk()),81.19192702451114,31.33308964526897)
-
1625867073422 -- - GaugeChange(Gauge(setGauge,Chunk()),87.07199284057864,46.517413177649566)
-
1625867079386 -- - GaugeChange(Gauge(setGauge,Chunk()),76.17035144725114,61.71045687993241)
-
1625867084484 -- - GaugeChange(Gauge(setGauge,Chunk()),52.3163908650382,32.18595537383532)
-
-
-

A diagram for adjustGauge

- -
1625867040364 -- - GaugeChange(Gauge(adjustGauge,Chunk()),29.73365745723163,20.8048762756599)
-
1625867044373 -- - GaugeChange(Gauge(adjustGauge,Chunk()),-1.3151015843323037,9.90352875659962)
-
1625867049371 -- - GaugeChange(Gauge(adjustGauge,Chunk()),20.466592588405135,-22.09476446231065)
-
1625867054373 -- - GaugeChange(Gauge(adjustGauge,Chunk()),19.104113525604603,32.543742877480575)
-
1625867060435 -- - GaugeChange(Gauge(adjustGauge,Chunk()),41.42644284347915,48.00813815764895)
-
1625867065379 -- - GaugeChange(Gauge(adjustGauge,Chunk()),46.380282372597364,3.1892001308431617)
-
1625867070386 -- - GaugeChange(Gauge(adjustGauge,Chunk()),39.53252257810665,84.78082938987001)
-
1625867075438 -- - GaugeChange(Gauge(adjustGauge,Chunk()),14.36631632930505,57.7212678307366)
-
1625867080437 -- - GaugeChange(Gauge(adjustGauge,Chunk()),35.831820563712796,4.506442161800962)
-
1625867085459 -- - GaugeChange(Gauge(adjustGauge,Chunk()),8.65748871765706,51.172570446136845)
-
-
-

A diagram for zmxHistogram

- -
1625867037549 -- - HistogramChange(Histogram(zmxHistogram,Chunk(0,10,20,30,40,50,60,70,80,90,100,1.7976931348623157e+308),Chunk()),MetricState(zmxHistogram, - DoubleHistogram(Chunk((0,0),(10,23),(20,34),(30,43),(40,53),(50,76),(60,95),(70,114),(80,127),(90,147),(100,160),(1.7976931348623157e+308,193)),193,11774.24056507966))) -
-
1625867042646 -- - HistogramChange(Histogram(zmxHistogram,Chunk(0,10,20,30,40,50,60,70,80,90,100,1.7976931348623157e+308),Chunk()),MetricState(zmxHistogram, - DoubleHistogram(Chunk((0,0),(10,24),(20,35),(30,45),(40,57),(50,80),(60,100),(70,119),(80,132),(90,152),(100,165),(1.7976931348623157e+308,198)),198,11931.82512670679))) -
-
1625867047592 -- - HistogramChange(Histogram(zmxHistogram,Chunk(0,10,20,30,40,50,60,70,80,90,100,1.7976931348623157e+308),Chunk()),MetricState(zmxHistogram, - DoubleHistogram(Chunk((0,0),(10,25),(20,36),(30,46),(40,58),(50,81),(60,102),(70,122),(80,135),(90,157),(100,170),(1.7976931348623157e+308,203)),203,12218.070255964714))) -
-
1625867052649 -- - HistogramChange(Histogram(zmxHistogram,Chunk(0,10,20,30,40,50,60,70,80,90,100,1.7976931348623157e+308),Chunk()),MetricState(zmxHistogram, - DoubleHistogram(Chunk((0,0),(10,25),(20,38),(30,48),(40,61),(50,84),(60,105),(70,126),(80,139),(90,162),(100,175),(1.7976931348623157e+308,208)),208,12436.04528747159))) -
-
1625867057596 -- - HistogramChange(Histogram(zmxHistogram,Chunk(0,10,20,30,40,50,60,70,80,90,100,1.7976931348623157e+308),Chunk()),MetricState(zmxHistogram, - DoubleHistogram(Chunk((0,0),(10,25),(20,38),(30,48),(40,61),(50,85),(60,106),(70,128),(80,142),(90,165),(100,178),(1.7976931348623157e+308,213)),213,12845.090891179085))) -
-
1625867062659 -- - HistogramChange(Histogram(zmxHistogram,Chunk(0,10,20,30,40,50,60,70,80,90,100,1.7976931348623157e+308),Chunk()),MetricState(zmxHistogram, - DoubleHistogram(Chunk((0,0),(10,25),(20,38),(30,48),(40,61),(50,85),(60,106),(70,129),(80,143),(90,167),(100,181),(1.7976931348623157e+308,218)),218,13306.280122930959))) -
-
1625867067590 -- - HistogramChange(Histogram(zmxHistogram,Chunk(0,10,20,30,40,50,60,70,80,90,100,1.7976931348623157e+308),Chunk()),MetricState(zmxHistogram, - DoubleHistogram(Chunk((0,0),(10,25),(20,39),(30,50),(40,63),(50,87),(60,108),(70,132),(80,146),(90,171),(100,185),(1.7976931348623157e+308,223)),223,13610.916447731193))) -
-
1625867072618 -- - HistogramChange(Histogram(zmxHistogram,Chunk(0,10,20,30,40,50,60,70,80,90,100,1.7976931348623157e+308),Chunk()),MetricState(zmxHistogram, - DoubleHistogram(Chunk((0,0),(10,25),(20,39),(30,51),(40,65),(50,90),(60,111),(70,135),(80,149),(90,175),(100,189),(1.7976931348623157e+308,228)),228,13924.054894567342))) -
-
1625867077632 -- - HistogramChange(Histogram(zmxHistogram,Chunk(0,10,20,30,40,50,60,70,80,90,100,1.7976931348623157e+308),Chunk()),MetricState(zmxHistogram, - DoubleHistogram(Chunk((0,0),(10,25),(20,39),(30,53),(40,67),(50,93),(60,114),(70,138),(80,153),(90,180),(100,194),(1.7976931348623157e+308,233)),233,14183.8497221766))) -
-
1625867082628 -- - HistogramChange(Histogram(zmxHistogram,Chunk(0,10,20,30,40,50,60,70,80,90,100,1.7976931348623157e+308),Chunk()),MetricState(zmxHistogram, - DoubleHistogram(Chunk((0,0),(10,25),(20,42),(30,56),(40,70),(50,97),(60,118),(70,142),(80,157),(90,185),(100,199),(1.7976931348623157e+308,238)),238,14368.65372212018))) -
-
-
-

A diagram for mySummary

- -
1625867038560 -- - SummaryChange(Summary(mySummary,PT24H,100,0.03,Chunk(0.1,0.5,0.9),Chunk()),MetricState(mySummary, - Summary(0.03,Chunk((0.1,Some(143)),(0.5,Some(275)),(0.9,Some(463))),194,58847)))
-
1625867043583 -- - SummaryChange(Summary(mySummary,PT24H,100,0.03,Chunk(0.1,0.5,0.9),Chunk()),MetricState(mySummary, - Summary(0.03,Chunk((0.1,Some(143)),(0.5,Some(260)),(0.9,Some(463))),199,59811)))
-
1625867048573 -- - SummaryChange(Summary(mySummary,PT24H,100,0.03,Chunk(0.1,0.5,0.9),Chunk()),MetricState(mySummary, - Summary(0.03,Chunk((0.1,Some(133)),(0.5,Some(253)),(0.9,Some(463))),204,60892)))
-
1625867053573 -- - SummaryChange(Summary(mySummary,PT24H,100,0.03,Chunk(0.1,0.5,0.9),Chunk()),MetricState(mySummary, - Summary(0.03,Chunk((0.1,Some(132)),(0.5,Some(248)),(0.9,Some(459))),209,61999)))
-
1625867058636 -- - SummaryChange(Summary(mySummary,PT24H,100,0.03,Chunk(0.1,0.5,0.9),Chunk()),MetricState(mySummary, - Summary(0.03,Chunk((0.1,Some(127)),(0.5,Some(250)),(0.9,Some(459))),214,63151)))
-
1625867063597 -- - SummaryChange(Summary(mySummary,PT24H,100,0.03,Chunk(0.1,0.5,0.9),Chunk()),MetricState(mySummary, - Summary(0.03,Chunk((0.1,Some(127)),(0.5,Some(245)),(0.9,Some(459))),219,64452)))
-
1625867069600 -- - SummaryChange(Summary(mySummary,PT24H,100,0.03,Chunk(0.1,0.5,0.9),Chunk()),MetricState(mySummary, - Summary(0.03,Chunk((0.1,Some(127)),(0.5,Some(248)),(0.9,Some(459))),225,66013)))
-
1625867074604 -- - SummaryChange(Summary(mySummary,PT24H,100,0.03,Chunk(0.1,0.5,0.9),Chunk()),MetricState(mySummary, - Summary(0.03,Chunk((0.1,Some(124)),(0.5,Some(248)),(0.9,Some(459))),230,67475)))
-
1625867078614 -- - SummaryChange(Summary(mySummary,PT24H,100,0.03,Chunk(0.1,0.5,0.9),Chunk()),MetricState(mySummary, - Summary(0.03,Chunk((0.1,Some(127)),(0.5,Some(248)),(0.9,Some(463))),234,68623)))
-
1625867084713 -- - SummaryChange(Summary(mySummary,PT24H,100,0.03,Chunk(0.1,0.5,0.9),Chunk()),MetricState(mySummary, - Summary(0.03,Chunk((0.1,Some(127)),(0.5,Some(250)),(0.9,Some(459))),240,70069)))
-
-
-

A diagram for mySet

- -
1625867037361 -- - SetChange(SetCount(mySet,token,Chunk()),MetricState(mySet, - SetCount(token,Chunk((myKey-17,18),(myKey-18,20),(myKey-19,20),(myKey-13,12),(myKey-14,19),(myKey-15,20),(myKey-16,21),(myKey-10,23),(myKey-11,17),(myKey-12,23))))) -
-
1625867042364 -- - SetChange(SetCount(mySet,token,Chunk()),MetricState(mySet, - SetCount(token,Chunk((myKey-17,19),(myKey-18,20),(myKey-19,20),(myKey-13,13),(myKey-14,20),(myKey-15,20),(myKey-16,21),(myKey-10,25),(myKey-11,17),(myKey-12,23))))) -
-
1625867047427 -- - SetChange(SetCount(mySet,token,Chunk()),MetricState(mySet, - SetCount(token,Chunk((myKey-17,20),(myKey-18,20),(myKey-19,20),(myKey-13,13),(myKey-14,20),(myKey-15,22),(myKey-16,21),(myKey-10,26),(myKey-11,18),(myKey-12,23))))) -
-
1625867052368 -- - SetChange(SetCount(mySet,token,Chunk()),MetricState(mySet, - SetCount(token,Chunk((myKey-17,21),(myKey-18,21),(myKey-19,21),(myKey-13,13),(myKey-14,20),(myKey-15,22),(myKey-16,22),(myKey-10,26),(myKey-11,18),(myKey-12,24))))) -
-
1625867057427 -- - SetChange(SetCount(mySet,token,Chunk()),MetricState(mySet, - SetCount(token,Chunk((myKey-17,22),(myKey-18,21),(myKey-19,21),(myKey-13,13),(myKey-14,21),(myKey-15,24),(myKey-16,23),(myKey-10,26),(myKey-11,18),(myKey-12,24))))) -
-
1625867062487 -- - SetChange(SetCount(mySet,token,Chunk()),MetricState(mySet, - SetCount(token,Chunk((myKey-17,23),(myKey-18,21),(myKey-19,23),(myKey-13,14),(myKey-14,21),(myKey-15,24),(myKey-16,23),(myKey-10,26),(myKey-11,18),(myKey-12,25))))) -
-
1625867067387 -- - SetChange(SetCount(mySet,token,Chunk()),MetricState(mySet, - SetCount(token,Chunk((myKey-17,24),(myKey-18,21),(myKey-19,24),(myKey-13,14),(myKey-14,21),(myKey-15,25),(myKey-16,24),(myKey-10,27),(myKey-11,18),(myKey-12,25))))) -
-
1625867072477 -- - SetChange(SetCount(mySet,token,Chunk()),MetricState(mySet, - SetCount(token,Chunk((myKey-17,24),(myKey-18,21),(myKey-19,25),(myKey-13,15),(myKey-14,21),(myKey-15,26),(myKey-16,24),(myKey-10,28),(myKey-11,18),(myKey-12,26))))) -
-
1625867078384 -- - SetChange(SetCount(mySet,token,Chunk()),MetricState(mySet, - SetCount(token,Chunk((myKey-17,24),(myKey-18,21),(myKey-19,25),(myKey-13,16),(myKey-14,22),(myKey-15,27),(myKey-16,24),(myKey-10,29),(myKey-11,18),(myKey-12,28))))) -
-
1625867083391 -- - SetChange(SetCount(mySet,token,Chunk()),MetricState(mySet, - SetCount(token,Chunk((myKey-17,24),(myKey-18,22),(myKey-19,25),(myKey-13,16),(myKey-14,24),(myKey-15,27),(myKey-16,24),(myKey-10,29),(myKey-11,20),(myKey-12,28))))) -
-
-
-
-
- - - \ No newline at end of file diff --git a/client/js/src/main/scala/index.css b/client/js/src/main/index.css similarity index 100% rename from client/js/src/main/scala/index.css rename to client/js/src/main/index.css diff --git a/docs/client/index.md b/docs/client/index.md new file mode 100644 index 00000000..01b009cf --- /dev/null +++ b/docs/client/index.md @@ -0,0 +1,87 @@ +--- +id: client_index +title: "WIP: Scala JS Client" +--- + +Even though the normal use case for ZMX is to use one of supported metric back ends, the ZMX team has decided +to provide a simplified client using ScalaJS, so users can explore metrics capturing and visual presentation +without having to install the pre-requisites for one of the back ends. + +> The ScalaJS client is not designed as a replacement for one of the dashboard implementations offering a +> much larger feature set. It is designed to quickly visualize ZMX metrics. + +## ZMX client technology stack + +### Server side + +On the server side we use a `MetricListener` implementation that is registered within the ZMX instrumented application. This listener is defined in `MetricsProtocol` and uses a `ZHub` under the covers to create a +stream of `MetricMessage`s. + +The `MetricsServer` uses that stream to create a websocket stream of binary encoded `MetricMessage` once it receives +a `Subscribe`message from a ScalaJS client. + +### Client side + +The ScalaJS client creates a websocket connection to the instrumented server and starts processing the inbound +stream of `MetricMessage`. + +The client is built on top of [Laminar](https://laminar.dev/), so the stream of inbound messages is turned into +a airstream, which is tightly integrated into Laminar. + +The incoming messages are summarized into tables, one table per metric type. Within each table, all of the distinct +metrics encountered so far are displayed in a single line per metric. All lines display the metric name and the labels defined for the metric. Also, each line is amended with some summary information depending on the metric type. + +![Metrics tables](/zio-zmx/img/jsclient-tables.png) + +On the left of each metric line a button `Add diagram` is located. A click on that button will create a diagram for +this particular metric to the `Diagrams`section of the page. + +At the moment all diagrams are line diagrams with a time scaled horizontal axis. A diagram will display the line(s) for a single metric, so in the case there will be one line only. For histogram there will be a line per bucket and also for the average. For summaries there will be a line per quantile and also for the average. For sets there will be a line for each distinct value of the set. + +Each diagram will update automatically according to the inbound stream of data. To make the update smoother, a diagram will sample the inbound data stream every 5 seconds and perform the refresh. Also, each diagram will capture +at most 100 time slots - forgetting the oldest entry once the buffer is filled up. + +![Counter Diagram](/zio-zmx/img/jsclient-countall.png) + +![Summary Diagram](/zio-zmx/img/jsclient-summary.png) + +## Working on the ZMX client + +To work on the client, besides `sbt` `node` has to be installed on the development machine. The directory `client/js` +is the base directory for all Node JS related tasks. + +### Prepare the environment + +1. At first, run `yarn install` within `client/js`. +1. Build the tailwind based CSS with `npx tailwind -i src/main/index.css -o ./target/rollup/main.css` + +### Build and run the instrumented server / client + +1. Start the instrumented Server with with web socket server from the ZMX checkout directory with `sbt clientJVM/run` +1. In another shell start a continuous compile of the Scala JS client code by starting a sbt shell and execute `~clientJS/fastOptJS`. This will recompile the Scala JS code upon each save of a related source file. +1. In yet another shell, from within `client/js` start `npx vite build -m development --watch`. This will repackage + the web application upon on each change. +1. In yet another shell, from within `client/js` start `npx vite`. This will start a local HTTP server on port + 3000 picking up the currently packaged application. `http://localhost:3000` will now display the client. + + In case you want to use a browser on a different machine than the machine where you have started the vite + server, you have to start the vite server with `npx vite --host 0.0.0.0`, so that the vite server starts to + listen on all network interfaces. + +### Ideas for further development (non-exhaustive) + +1. We want to be able to edit the diagrams. At a minimum we want to set the refresh interval per diagram and also the + buffer size that determines how many time slots are being kept for the diagram. +1. Ideally we could change the color for each line displayed in a diagram. +1. We want to have each diagram have an editable title. +1. In each diagram, we want to have the option of adding more metrics to the same diagram. +1. It might make sense to change the diagram type, for example a bar chart or pie chart might make sense for sets. +1. Ideally, the configuration for each diagram could be captured in a JSON serializable case class, so that we could + store the state of all diagrams currently displayed within the web page to JSON. We could have a dialog where we + could simply display the current JSON to copy it into a file and another dialog to paste a JSON config for setting + the diagram state. Potentially we could use local browser storage for storing and retrieving JSON. + + + + + diff --git a/docs/overview/metrics.md b/docs/overview/metrics.md index 04d05ce5..060c5d55 100644 --- a/docs/overview/metrics.md +++ b/docs/overview/metrics.md @@ -17,8 +17,8 @@ made or in cases when the platform might not be feasible to use in development. For a sneak preview, building a ZMX metrics client was the topic of two live coding sessions on Twitch TV: Building a ZMX metrics client [Part I](https://www.twitch.tv/kitlangton/video/1038831171) and [Part II](https://www.twitch.tv/kitlangton/video/1038926026) -> Changing the targeted reporting back end will have no impact on the application at all. Once instrumented properly, that reporting back decision will happen __at the end of the world__ -> in the ZIP applications mainline by injecting one or more of the available reporting clients. +> Changing the targeted reporting back end will have no impact on the application at all. Once instrumented properly, that reporting back end decision will happen __at the end of the world__ +> in the ZIO applications mainline by injecting one or more of the available reporting clients. Currently ZMX provides mappings to [StatsD](https://docs.datadoghq.com/) and [Prometheus](https://prometheus.io/) out of the box. diff --git a/website/pages/en/index.js b/website/pages/en/index.js index f4a311d1..89ff4c1b 100755 --- a/website/pages/en/index.js +++ b/website/pages/en/index.js @@ -15,8 +15,8 @@ const GridBlock = CompLibrary.GridBlock; class HomeSplash extends React.Component { render() { - const {siteConfig, language = ''} = this.props; - const {baseUrl, docsUrl} = siteConfig; + const { siteConfig, language = '' } = this.props; + const { baseUrl, docsUrl } = siteConfig; const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`; const langPart = `${language ? `${language}/` : ''}`; const docUrl = doc => `${baseUrl}${docsPart}${langPart}${doc}`; @@ -31,7 +31,7 @@ class HomeSplash extends React.Component { const Logo = props => (
- Project Logo + Project Logo
); @@ -61,10 +61,10 @@ class HomeSplash extends React.Component { return (
- + - +
@@ -75,8 +75,8 @@ class HomeSplash extends React.Component { class Index extends React.Component { render() { - const {config: siteConfig, language = ''} = this.props; - const {baseUrl} = siteConfig; + const { config: siteConfig, language = '' } = this.props; + const { baseUrl } = siteConfig; const Block = props => ( - +
{/* */} {/* */} diff --git a/website/sidebars.json b/website/sidebars.json index bd74e418..d29bc7d0 100755 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -14,9 +14,9 @@ "metrics/metrics_example" ] }, - "usecases-sidebar": { - "Use Cases": [ - "usecases/usecases_index" + "client-sidebar": { + "ScalaJS Client": [ + "client/client_index" ] }, "about-sidebar": { diff --git a/website/siteConfig.js b/website/siteConfig.js index 1b63e3cf..32662376 100644 --- a/website/siteConfig.js +++ b/website/siteConfig.js @@ -31,10 +31,10 @@ const siteConfig = { // For no header links in the top nav bar -> headerLinks: [], headerLinks: [ - {doc: 'overview/overview_index', label: 'Overview'}, - {doc: 'metrics/metrics_index', label: 'Metrics'}, - {doc: 'usecases/usecases_index', label: 'Use Cases'}, - {doc: 'about/about_index', label: 'About'} + { doc: 'overview/overview_index', label: 'Overview' }, + { doc: 'metrics/metrics_index', label: 'Metrics' }, + { doc: 'client/client_index', label: 'ScalaJS Client' }, + { doc: 'about/about_index', label: 'About' } ], // by default Docusaurus combines CSS files in a way that doesn't play nicely with Scaladoc diff --git a/website/static/img/jsclient-countall.png b/website/static/img/jsclient-countall.png new file mode 100644 index 00000000..bd446672 Binary files /dev/null and b/website/static/img/jsclient-countall.png differ diff --git a/website/static/img/jsclient-summary.png b/website/static/img/jsclient-summary.png new file mode 100644 index 00000000..e8a19b5f Binary files /dev/null and b/website/static/img/jsclient-summary.png differ diff --git a/website/static/img/jsclient-tables.png b/website/static/img/jsclient-tables.png new file mode 100644 index 00000000..9324f40f Binary files /dev/null and b/website/static/img/jsclient-tables.png differ