Compare commits
No commits in common. "main" and "gh-pages" have entirely different histories.
16 changed files with 827 additions and 417 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,4 +0,0 @@
|
||||||
_build/
|
|
||||||
.merlin
|
|
||||||
*.install
|
|
||||||
.*.swp
|
|
22
CHANGES.md
22
CHANGES.md
|
@ -1,22 +0,0 @@
|
||||||
# v0.0.5 (2024-04-10)
|
|
||||||
|
|
||||||
* Update to mirage-runtime 4.5.0 API changes (Arg.log_threshold is now
|
|
||||||
Conv.log_threshold)
|
|
||||||
|
|
||||||
# v0.0.4 (2023-03-05)
|
|
||||||
|
|
||||||
* Remove mirage-solo5 dependency, now that mirage-solo5 and mirage-xen install
|
|
||||||
a memory metrics themselves
|
|
||||||
|
|
||||||
# v0.0.3 (2022-09-26)
|
|
||||||
|
|
||||||
* Upgrade to Mirage 4.3.0+
|
|
||||||
|
|
||||||
# v0.0.2 (2022-08-08)
|
|
||||||
|
|
||||||
* Upgrade to MirageOS4 (mirage-solo5 >= 0.7.0), drop usage of deprecated
|
|
||||||
OS.MM.malloc_metrics
|
|
||||||
|
|
||||||
# v0.0.1 (2022-05-22)
|
|
||||||
|
|
||||||
* Initial public release
|
|
51
README.md
51
README.md
|
@ -1,51 +0,0 @@
|
||||||
# Grafana MirageOS Unikernel monitoring
|
|
||||||
|
|
||||||
Using Influx, Telegraf, etc.
|
|
||||||
|
|
||||||
![Monitoring](https://raw.githubusercontent.com/robur-coop/mirage-monitoring/main/one.png)
|
|
||||||
|
|
||||||
Best used on a private network interface for your unikernel.
|
|
||||||
|
|
||||||
# Output metrics to influx / telegraf
|
|
||||||
|
|
||||||
The provided `ip:port` in `create` is used to send every `interval` seconds
|
|
||||||
gathered metrics to, using the Influx wire protocol.
|
|
||||||
|
|
||||||
# Dynamic adjustments of Log level and Metrics reporting
|
|
||||||
|
|
||||||
The `create` function has a *listener_port* argument (defaulting to 2323). On the
|
|
||||||
customizable port TCP connections to the unikernel are possible. Each connection
|
|
||||||
can transmit a command (as text) to adjust log level and enable or disable
|
|
||||||
metrics sources:
|
|
||||||
|
|
||||||
The log level (prefix `L`) is specified, the same as the command-line argument `-l`:
|
|
||||||
- `L*:debug` all log sources are enabled on the *debug* level.
|
|
||||||
- `Lmonitoring-experiments:error` the log source monitoring-experiments is set to the *error* level.
|
|
||||||
- `L*:info,monitoring-experiments:debug` all log sources are enabled on the *info* level, and the log source monitoring-experiments is set to the *debug* level.
|
|
||||||
|
|
||||||
The metrics (prefix `M`) sources can be enabled and disabled based on source name.
|
|
||||||
First, if present, the all command is executed, then the tags, then specific sources:
|
|
||||||
- `M*:disable,memory:enable,net-solo5:enable` disables all metrics sources, and then enables *memory* and *net-solo5*.
|
|
||||||
- `Mnet-solo5:disable` disables the *net-solo5* metrics source.
|
|
||||||
- `Mtag:http:enable` enables all metrics with the *http* tag.
|
|
||||||
|
|
||||||
The log levels for the log sources can be inspected:
|
|
||||||
- `l` reports the default log level and the log level for all log sources with a different log level.
|
|
||||||
- `l*` reports the default log level and the log level for all log sources.
|
|
||||||
- `lmonitoring-experiments,dns` reports the log level for monitoring-experiments and dns respectively.
|
|
||||||
|
|
||||||
Likewise, metrics status can be similarly inspected:
|
|
||||||
- `m` reports the default metrics status and the metrics status for all metrics sources with a different status.
|
|
||||||
- `m*` reports the default metrics status, all enabled tags, and the metrics status of all metrics sources.
|
|
||||||
- `mmemory,net-solo5` reports the metrics status for memory and net-solo5 respectively.
|
|
||||||
|
|
||||||
# Memprof tracing
|
|
||||||
|
|
||||||
The `create` function has a `memtrace_port` argument (defualts to 4242). On this
|
|
||||||
port, when a TCP client connects,
|
|
||||||
[OCaml memory profiling](https://ocaml.org/api/Gc.Memprof.html) is started and
|
|
||||||
dumped to the client. The `sampling_rate` (defaults to 1e-4) is used. This uses
|
|
||||||
the [memprof-mirage](https://github.com/hannesm/memprof-mirage) package.
|
|
||||||
|
|
||||||
The output trace is best being viewed with
|
|
||||||
[memtrace_viewer](https://github.com/janestreet/memtrace_viewer/).
|
|
|
@ -1,2 +0,0 @@
|
||||||
(lang dune 1.0)
|
|
||||||
(name mirage-monitoring)
|
|
2
highlight.pack.js
Normal file
2
highlight.pack.js
Normal file
File diff suppressed because one or more lines are too long
19
index.html
Normal file
19
index.html
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title>index</title>
|
||||||
|
<link rel="stylesheet" href="./odoc.css"/>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="content">
|
||||||
|
<div class="by-name">
|
||||||
|
<h2>OCaml package documentation</h2>
|
||||||
|
<ol>
|
||||||
|
<li><a href="mirage-monitoring/index.html">mirage-monitoring</a> <span class="version">0.0.2</span></li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,36 +0,0 @@
|
||||||
opam-version: "2.0"
|
|
||||||
maintainer: "Robur <team@robur.coop>"
|
|
||||||
authors: ["Robur <team@robur.coop>"]
|
|
||||||
homepage: "https://github.com/robur-coop/mirage-monitoring"
|
|
||||||
doc: "https://robur-coop.github.io/mirage-monitoring"
|
|
||||||
dev-repo: "git+https://github.com/robur-coop/mirage-monitoring.git"
|
|
||||||
bug-reports: "https://github.com/robur-coop/mirage-monitoring/issues"
|
|
||||||
license: "AGPL-3.0-only"
|
|
||||||
|
|
||||||
depends: [
|
|
||||||
"ocaml" {>= "4.11.0"}
|
|
||||||
"dune"
|
|
||||||
"logs" {>= "0.6.3"}
|
|
||||||
"metrics" {>= "0.4.0"}
|
|
||||||
"metrics-lwt" {>= "0.2.0"}
|
|
||||||
"metrics-influx" {>= "0.2.0"}
|
|
||||||
"mirage-time" {>= "2.0.0"}
|
|
||||||
"tcpip" {>= "7.0.0"}
|
|
||||||
"mirage-runtime" {>= "4.5.0"}
|
|
||||||
"memtrace-mirage" {>= "0.2.1.2.2"}
|
|
||||||
"mirage-clock" {>= "4.0.0"}
|
|
||||||
]
|
|
||||||
conflicts: [
|
|
||||||
"mirage-solo5" {< "0.9.2"}
|
|
||||||
"mirage-xen" {< "8.0.2"}
|
|
||||||
]
|
|
||||||
build: [
|
|
||||||
["dune" "subst"] {dev}
|
|
||||||
["dune" "build" "-p" name "-j" jobs]
|
|
||||||
["dune" "runtest" "-p" name "-j" jobs] {with-test}
|
|
||||||
]
|
|
||||||
synopsis: "Monitoring of MirageOS unikernels"
|
|
||||||
description: """
|
|
||||||
Reporting metrics to Influx, Telegraf. Dynamic adjusting log level and metrics
|
|
||||||
sources, memprof profiling.
|
|
||||||
"""
|
|
12
mirage-monitoring/Mirage_monitoring/Make/index.html
Normal file
12
mirage-monitoring/Mirage_monitoring/Make/index.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Make (mirage-monitoring.Mirage_monitoring.Make)</title><link rel="stylesheet" href="../../../odoc.css"/><meta charset="utf-8"/><meta name="generator" content="odoc 2.1.1"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/><script src="../../../highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body class="odoc"><nav class="odoc-nav"><a href="../index.html">Up</a> – <a href="../../index.html">mirage-monitoring</a> » <a href="../index.html">Mirage_monitoring</a> » Make</nav><header class="odoc-preamble"><h1>Module <code><span>Mirage_monitoring.Make</span></code></h1></header><nav class="odoc-toc"><ul><li><a href="#parameters">Parameters</a></li><li><a href="#signature">Signature</a></li></ul></nav><div class="odoc-content"><h2 id="parameters"><a href="#parameters" class="anchor"></a>Parameters</h2><div class="odoc-spec"><div class="spec parameter" id="argument-1-T" class="anchored"><a href="#argument-1-T" class="anchor"></a><code><span><span class="keyword">module</span> </span><span>T</span><span> : <span class="xref-unresolved">Mirage_time</span>.S</span></code></div></div><div class="odoc-spec"><div class="spec parameter" id="argument-2-P" class="anchored"><a href="#argument-2-P" class="anchor"></a><code><span><span class="keyword">module</span> </span><span>P</span><span> : <span class="xref-unresolved">Mirage_clock</span>.PCLOCK</span></code></div></div><div class="odoc-spec"><div class="spec parameter" id="argument-3-S" class="anchored"><a href="#argument-3-S" class="anchor"></a><code><span><span class="keyword">module</span> </span><span>S</span><span> : <span class="xref-unresolved">Tcpip</span>.Stack.V4V6</span></code></div></div><h2 id="signature"><a href="#signature" class="anchor"></a>Signature</h2><div class="odoc-spec"><div class="spec value" id="val-create" class="anchored"><a href="#val-create" class="anchor"></a><code><span><span class="keyword">val</span> create :
|
||||||
|
<span>?interval:int <span class="arrow">-></span></span>
|
||||||
|
<span>?quick:bool <span class="arrow">-></span></span>
|
||||||
|
<span>?hostname:string <span class="arrow">-></span></span>
|
||||||
|
<span><span class="xref-unresolved">Ipaddr</span>.t <span class="arrow">-></span></span>
|
||||||
|
<span>?port:int <span class="arrow">-></span></span>
|
||||||
|
<span>?listen_port:int <span class="arrow">-></span></span>
|
||||||
|
<span>?memtrace_port:int <span class="arrow">-></span></span>
|
||||||
|
<span>?sampling_rate:float <span class="arrow">-></span></span>
|
||||||
|
<span><span class="xref-unresolved">S</span>.t <span class="arrow">-></span></span>
|
||||||
|
unit</span></code></div><div class="spec-doc"><p><code>create ~interval ~quick ~hostname ip ~port ~listen_port ~memtrace_port ~sampling_rate stack</code> initiates monitoring on <code>stack</code> for the unikernel. The metrics are reported every <code>interval</code> (defaults to 10) seconds to <code>ip</code> on <code>port</code> (defaults to 8094) via TCP using the influxd wire protocol. On <code>listen_port</code> (defaults to 2323) a TCP connection can be initiated to adjust the log level and enable and disable metrics sources. On <code>memtrace_port</code> (defaults to 4242) a single TCP client can connect simultaneously to receive a <code>Gc.Memprof</code> trace. The <code>sampling_rate</code> defaults to <code>1e-4</code>. If <code>quick</code> is provided and <code>false</code> (defaults to <code>true</code>), <code>Solo5_os.Memory.stat</code> is used, otherwise <code>Solo5_os.Memory.quick_stat</code> is used.</p></div></div></div></body></html>
|
9
mirage-monitoring/Mirage_monitoring/index.html
Normal file
9
mirage-monitoring/Mirage_monitoring/index.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Mirage_monitoring (mirage-monitoring.Mirage_monitoring)</title><link rel="stylesheet" href="../../odoc.css"/><meta charset="utf-8"/><meta name="generator" content="odoc 2.1.1"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/><script src="../../highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body class="odoc"><nav class="odoc-nav"><a href="../index.html">Up</a> – <a href="../index.html">mirage-monitoring</a> » Mirage_monitoring</nav><header class="odoc-preamble"><h1>Module <code><span>Mirage_monitoring</span></code></h1></header><div class="odoc-content"><div class="odoc-spec"><div class="spec value" id="val-counter_metrics" class="anchored"><a href="#val-counter_metrics" class="anchor"></a><code><span><span class="keyword">val</span> counter_metrics :
|
||||||
|
<span>f:<span>( <span><span class="type-var">'a</span> <span class="arrow">-></span></span> string )</span> <span class="arrow">-></span></span>
|
||||||
|
<span>string <span class="arrow">-></span></span>
|
||||||
|
<span><span>( <span><span class="xref-unresolved">Metrics</span>.field list</span>, <span><span class="type-var">'a</span> <span class="arrow">-></span></span> <span class="xref-unresolved">Metrics</span>.data )</span> <span class="xref-unresolved">Metrics</span>.src</span></span></code></div></div><div class="odoc-spec"><div class="spec value" id="val-vmname" class="anchored"><a href="#val-vmname" class="anchor"></a><code><span><span class="keyword">val</span> vmname : <span>string <span class="arrow">-></span></span> <span class="xref-unresolved">Metrics</span>.field</span></code></div><div class="spec-doc"><p><code>vmname name</code> creates a <code>tag</code> with the virtual machine name.</p></div></div><div class="odoc-spec"><div class="spec module" id="module-Make" class="anchored"><a href="#module-Make" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Make/index.html">Make</a></span><span>
|
||||||
|
(<a href="Make/index.html#argument-1-T">T</a> : <span class="xref-unresolved">Mirage_time</span>.S)
|
||||||
|
(<a href="Make/index.html#argument-2-P">P</a> : <span class="xref-unresolved">Mirage_clock</span>.PCLOCK)
|
||||||
|
(<a href="Make/index.html#argument-3-S">S</a> : <span class="xref-unresolved">Tcpip</span>.Stack.V4V6) :
|
||||||
|
<span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div></div></div></body></html>
|
2
mirage-monitoring/index.html
Normal file
2
mirage-monitoring/index.html
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>index (mirage-monitoring.index)</title><link rel="stylesheet" href="../odoc.css"/><meta charset="utf-8"/><meta name="generator" content="odoc 2.1.1"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/><script src="../highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body class="odoc"><nav class="odoc-nav"><a href="../index.html">Up</a> – mirage-monitoring</nav><header class="odoc-preamble"><h1 id="mirage-monitoring-index"><a href="#mirage-monitoring-index" class="anchor"></a>mirage-monitoring index</h1></header><nav class="odoc-toc"><ul><li><a href="#library-mirage-monitoring">Library mirage-monitoring</a></li></ul></nav><div class="odoc-content"><h2 id="library-mirage-monitoring"><a href="#library-mirage-monitoring" class="anchor"></a>Library mirage-monitoring</h2><p>The entry point of this library is the module: <a href="Mirage_monitoring/index.html"><code>Mirage_monitoring</code></a>.</p></div></body></html>
|
783
odoc.css
Normal file
783
odoc.css
Normal file
|
@ -0,0 +1,783 @@
|
||||||
|
@charset "UTF-8";
|
||||||
|
/* Copyright (c) 2016 The odoc contributors. All rights reserved.
|
||||||
|
Distributed under the ISC license, see terms at the end of the file.
|
||||||
|
odoc 2.1.1 */
|
||||||
|
|
||||||
|
/* Fonts */
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Fira+Mono:400,500');
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Noticia+Text:400,400i,700');
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Fira+Sans:400,400i,500,500i,600,600i,700,700i');
|
||||||
|
|
||||||
|
:root,
|
||||||
|
.light:root {
|
||||||
|
--main-background: #FFFFFF;
|
||||||
|
|
||||||
|
--color: #333333;
|
||||||
|
--link-color: #2C94BD;
|
||||||
|
--anchor-hover: #555;
|
||||||
|
--anchor-color: #d5d5d5;
|
||||||
|
--xref-shadow: #cc6666;
|
||||||
|
--header-shadow: #ddd;
|
||||||
|
--by-name-version-color: #aaa;
|
||||||
|
--by-name-nav-link-color: #222;
|
||||||
|
--target-background: rgba(187, 239, 253, 0.3);
|
||||||
|
--target-shadow: rgba(187, 239, 253, 0.8);
|
||||||
|
--pre-border-color: #eee;
|
||||||
|
--code-background: #f6f8fa;
|
||||||
|
|
||||||
|
--li-code-background: #f6f8fa;
|
||||||
|
--li-code-color: #0d2b3e;
|
||||||
|
--toc-color: #1F2D3D;
|
||||||
|
--toc-before-color: #777;
|
||||||
|
--toc-background: #f6f8fa;
|
||||||
|
--toc-list-border: #ccc;
|
||||||
|
|
||||||
|
--spec-summary-border-color: #5c9cf5;
|
||||||
|
--spec-summary-background: var(--code-background);
|
||||||
|
--spec-summary-hover-background: #ebeff2;
|
||||||
|
--spec-details-after-background: rgba(0, 4, 15, 0.05);
|
||||||
|
--spec-details-after-shadow: rgba(204, 204, 204, 0.53);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark:root {
|
||||||
|
--main-background: #202020;
|
||||||
|
--code-background: #222;
|
||||||
|
--line-numbers-background: rgba(0, 0, 0, 0.125);
|
||||||
|
--navbar-background: #202020;
|
||||||
|
|
||||||
|
--color: #bebebe;
|
||||||
|
--dirname-color: #666;
|
||||||
|
--underline-color: #444;
|
||||||
|
--visited-color: #002800;
|
||||||
|
--visited-number-color: #252;
|
||||||
|
--unvisited-color: #380000;
|
||||||
|
--unvisited-number-color: #622;
|
||||||
|
--somevisited-color: #303000;
|
||||||
|
--highlight-color: #303e3f;
|
||||||
|
--line-number-color: rgba(230, 230, 230, 0.3);
|
||||||
|
--unvisited-margin-color: #622;
|
||||||
|
--border: #333;
|
||||||
|
--navbar-border: #333;
|
||||||
|
--code-color: #ccc;
|
||||||
|
|
||||||
|
--li-code-background: #373737;
|
||||||
|
--li-code-color: #999;
|
||||||
|
--toc-color: #777;
|
||||||
|
--toc-background: #252525;
|
||||||
|
|
||||||
|
--hljs-link: #999;
|
||||||
|
--hljs-keyword: #cda869;
|
||||||
|
--hljs-regexp: #f9ee98;
|
||||||
|
--hljs-title: #dcdcaa;
|
||||||
|
--hljs-type: #ac885b;
|
||||||
|
--hljs-meta: #82aaff;
|
||||||
|
--hljs-variable: #cf6a4c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--main-background: #202020;
|
||||||
|
--code-background: #333;
|
||||||
|
--line-numbers-background: rgba(0, 0, 0, 0.125);
|
||||||
|
--navbar-background: #202020;
|
||||||
|
|
||||||
|
--meter-unvisited-color: #622;
|
||||||
|
--meter-visited-color: #252;
|
||||||
|
--meter-separator-color: black;
|
||||||
|
|
||||||
|
--color: #bebebe;
|
||||||
|
--dirname-color: #666;
|
||||||
|
--underline-color: #444;
|
||||||
|
--visited-color: #002800;
|
||||||
|
--visited-number-color: #252;
|
||||||
|
--unvisited-color: #380000;
|
||||||
|
--unvisited-number-color: #622;
|
||||||
|
--somevisited-color: #303000;
|
||||||
|
--highlight-color: #303e3f;
|
||||||
|
--line-number-color: rgba(230, 230, 230, 0.3);
|
||||||
|
--unvisited-margin-color: #622;
|
||||||
|
--border: #333;
|
||||||
|
--navbar-border: #333;
|
||||||
|
--code-color: #ccc;
|
||||||
|
--by-name-nav-link-color: var(--color);
|
||||||
|
|
||||||
|
--li-code-background: #373737;
|
||||||
|
--li-code-color: #999;
|
||||||
|
--toc-color: #777;
|
||||||
|
--toc-before-color: #777;
|
||||||
|
--toc-background: #252525;
|
||||||
|
--toc-list-border: #ccc;
|
||||||
|
--spec-summary-hover-background: #ebeff2;
|
||||||
|
--spec-details-after-background: rgba(0, 4, 15, 0.05);
|
||||||
|
--spec-details-after-shadow: rgba(204, 204, 204, 0.53);
|
||||||
|
|
||||||
|
--hljs-link: #999;
|
||||||
|
--hljs-keyword: #cda869;
|
||||||
|
--hljs-regexp: #f9ee98;
|
||||||
|
--hljs-title: #dcdcaa;
|
||||||
|
--hljs-type: #ac885b;
|
||||||
|
--hljs-meta: #82aaff;
|
||||||
|
--hljs-variable: #cf6a4c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset a few things. */
|
||||||
|
|
||||||
|
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*, *:before, *:after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
text-align: left;
|
||||||
|
background: #FFFFFF;
|
||||||
|
color: var(--color);
|
||||||
|
background-color: var(--main-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
max-width: 100ex;
|
||||||
|
margin-left: calc(10vw + 20ex);
|
||||||
|
margin-right: 4ex;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
font-family: "Noticia Text", Georgia, serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
font-family: "Fira Sans", Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Basic markup elements */
|
||||||
|
|
||||||
|
b, strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
em, i em.odd{
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
em.odd, i em {
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
vertical-align: super;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
vertical-align: sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup, sub {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 0;
|
||||||
|
margin-left: 0.2ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul, ol {
|
||||||
|
list-style-position: outside
|
||||||
|
}
|
||||||
|
|
||||||
|
ul>li {
|
||||||
|
margin-left: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol>li {
|
||||||
|
margin-left: 27.2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li>*:first-child {
|
||||||
|
margin-top: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text alignements, this should be forbidden. */
|
||||||
|
|
||||||
|
.left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Links and anchors */
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--link-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
box-shadow: 0 1px 0 0 var(--link-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Linked highlight */
|
||||||
|
*:target {
|
||||||
|
background-color: var(--target-background) !important;
|
||||||
|
box-shadow: 0 0px 0 1px var(--target-shadow) !important;
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*:hover > a.anchor {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.anchor:before {
|
||||||
|
content: "#";
|
||||||
|
}
|
||||||
|
|
||||||
|
a.anchor:hover {
|
||||||
|
box-shadow: none;
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--anchor-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.anchor {
|
||||||
|
visibility: hidden;
|
||||||
|
position: absolute;
|
||||||
|
/* top: 0px; */
|
||||||
|
/* margin-left: -3ex; */
|
||||||
|
margin-left: -1.3em;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
padding-right: 0.4em;
|
||||||
|
padding-left: 0.4em;
|
||||||
|
/* To remain selectable */
|
||||||
|
color: var(--anchor-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.spec > a.anchor {
|
||||||
|
margin-left: -2.3em;
|
||||||
|
padding-right: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xref-unresolved {
|
||||||
|
color: #2C94BD;
|
||||||
|
}
|
||||||
|
.xref-unresolved:hover {
|
||||||
|
box-shadow: 0 1px 0 0 var(--xref-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Section and document divisions.
|
||||||
|
Until at least 4.03 many of the modules of the stdlib start at .h7,
|
||||||
|
we restart the sequence there like h2 */
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6, .h7, .h8, .h9, .h10 {
|
||||||
|
font-family: "Fira Sans", Helvetica, Arial, sans-serif;
|
||||||
|
font-weight: 400;
|
||||||
|
padding-top: 0.1em;
|
||||||
|
line-height: 1.2;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 2.441em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1.953em;
|
||||||
|
box-shadow: 0 1px 0 0 var(--header-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.563em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
small, .font_small {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 code, h1 tt {
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 code, h2 tt {
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 code, h3 tt {
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 code, h3 tt {
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 1.12em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comment delimiters, hidden but accessible to screen readers and
|
||||||
|
selected for copy/pasting */
|
||||||
|
|
||||||
|
/* Taken from bootstrap */
|
||||||
|
/* See also https://stackoverflow.com/a/27769435/4220738 */
|
||||||
|
.comment-delim {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preformatted and code */
|
||||||
|
|
||||||
|
tt, code, pre {
|
||||||
|
font-family: "Fira Mono", courier;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
padding: 0.1em;
|
||||||
|
border: 1px solid var(--pre-border-color);
|
||||||
|
border-radius: 5px;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
p code,
|
||||||
|
li code {
|
||||||
|
background-color: var(--li-code-background);
|
||||||
|
color: var(--li-code-color);
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0 0.3ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
p a > code {
|
||||||
|
color: var(--link-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code blocks (e.g. Examples) */
|
||||||
|
|
||||||
|
pre code {
|
||||||
|
font-size: 0.893rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code lexemes */
|
||||||
|
|
||||||
|
.keyword {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow { white-space: nowrap }
|
||||||
|
|
||||||
|
/* Module member specification */
|
||||||
|
|
||||||
|
.spec {
|
||||||
|
background-color: var(--spec-summary-background);
|
||||||
|
border-radius: 3px;
|
||||||
|
border-left: 4px solid var(--spec-summary-border-color);
|
||||||
|
border-right: 5px solid transparent;
|
||||||
|
padding: 0.35em 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.def-doc {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spacing between items */
|
||||||
|
div.odoc-spec,.odoc-include {
|
||||||
|
margin-bottom: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spec.type .variant {
|
||||||
|
margin-left: 2ch;
|
||||||
|
}
|
||||||
|
.spec.type .variant p {
|
||||||
|
margin: 0;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.spec.type .record {
|
||||||
|
margin-left: 2ch;
|
||||||
|
}
|
||||||
|
.spec.type .record p {
|
||||||
|
margin: 0;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.def {
|
||||||
|
margin-top: 0;
|
||||||
|
text-indent: -2ex;
|
||||||
|
padding-left: 2ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.def+div.def-doc {
|
||||||
|
margin-left: 1ex;
|
||||||
|
margin-top: 2.5px
|
||||||
|
}
|
||||||
|
|
||||||
|
div.def-doc>*:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Collapsible inlined include and module */
|
||||||
|
|
||||||
|
.odoc-include details {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.odoc-include.shadowed-include {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.odoc-include details:after {
|
||||||
|
z-index: -100;
|
||||||
|
display: block;
|
||||||
|
content: " ";
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 0 1ex 1ex 0;
|
||||||
|
right: -20px;
|
||||||
|
top: 1px;
|
||||||
|
bottom: 1px;
|
||||||
|
width: 15px;
|
||||||
|
background: var(--spec-details-after-background, rgba(0, 4, 15, 0.05));
|
||||||
|
box-shadow: 0 0px 0 1px var(--spec-details-after-shadow, rgba(204, 204, 204, 0.53));
|
||||||
|
}
|
||||||
|
|
||||||
|
.odoc-include summary {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.odoc-include summary:hover {
|
||||||
|
background-color: var(--spec-summary-hover-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Does not work in Firefox. */
|
||||||
|
.odoc-include summary::-webkit-details-marker {
|
||||||
|
color: #888;
|
||||||
|
transform: scaleX(-1);
|
||||||
|
position: absolute;
|
||||||
|
top: calc(50% - 5px);
|
||||||
|
height: 11px;
|
||||||
|
right: -29px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Records and variants FIXME */
|
||||||
|
|
||||||
|
div.def table {
|
||||||
|
text-indent: 0em;
|
||||||
|
padding: 0;
|
||||||
|
margin-left: -2ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.def {
|
||||||
|
padding-left: 2ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.def-doc *:first-child {
|
||||||
|
margin-top: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lists of @tags */
|
||||||
|
|
||||||
|
.at-tags { list-style-type: none; margin-left: -3ex; }
|
||||||
|
.at-tags li { padding-left: 3ex; text-indent: -3ex; }
|
||||||
|
.at-tags .at-tag { text-transform: capitalize }
|
||||||
|
|
||||||
|
/* Lists of modules */
|
||||||
|
|
||||||
|
.modules { list-style-type: none; margin-left: -3ex; }
|
||||||
|
.modules li { padding-left: 3ex; text-indent: -3ex; margin-top: 5px }
|
||||||
|
.modules .synopsis { padding-left: 1ch; }
|
||||||
|
|
||||||
|
/* Odig package index */
|
||||||
|
|
||||||
|
.packages { list-style-type: none; margin-left: -3ex; }
|
||||||
|
.packages li { padding-left: 3ex; text-indent: -3ex }
|
||||||
|
.packages li a.anchor { padding-right: 0.5ch; padding-left: 3ch; }
|
||||||
|
.packages .version { font-size: 10px; color: var(--by-name-version-color); }
|
||||||
|
.packages .synopsis { padding-left: 1ch }
|
||||||
|
|
||||||
|
.by-name nav a {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 18px;
|
||||||
|
margin-right: 1ex;
|
||||||
|
color: var(--by-name-nav-link-color,);
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.by-tag nav a {
|
||||||
|
margin-right: 1ex;
|
||||||
|
color: var(--by-name-nav-link-color);
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.by-tag ol { list-style-type: none; }
|
||||||
|
.by-tag ol.tags li { margin-left: 1ch; display: inline-block }
|
||||||
|
.by-tag td:first-child { text-transform: uppercase; }
|
||||||
|
|
||||||
|
/* Odig package page */
|
||||||
|
|
||||||
|
.package nav {
|
||||||
|
display: inline;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package .version {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package.info {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package.info td:first-child {
|
||||||
|
font-style: italic;
|
||||||
|
padding-right: 2ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package.info ul {
|
||||||
|
list-style-type: none;
|
||||||
|
display: inline;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package.info li {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0;
|
||||||
|
margin-right: 1ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#info-authors li, #info-maintainers li {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sidebar and TOC */
|
||||||
|
|
||||||
|
.odoc-toc:before {
|
||||||
|
display: block;
|
||||||
|
content: "Contents";
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 1em;
|
||||||
|
margin: 1.414em 0 0.5em;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--toc-before-color);
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.odoc-toc {
|
||||||
|
position: fixed;
|
||||||
|
top: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
left: 0px;
|
||||||
|
max-width: 30ex;
|
||||||
|
min-width: 26ex;
|
||||||
|
width: 20%;
|
||||||
|
background: var(--toc-background);
|
||||||
|
overflow: auto;
|
||||||
|
color: var(--toc-color);
|
||||||
|
padding-left: 2ex;
|
||||||
|
padding-right: 2ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.odoc-toc ul li a {
|
||||||
|
font-family: "Fira Sans", sans-serif;
|
||||||
|
font-size: 0.95em;
|
||||||
|
color: var(--color);
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.6em;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.odoc-toc ul li a:hover {
|
||||||
|
box-shadow: none;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First level titles */
|
||||||
|
|
||||||
|
.odoc-toc>ul>li>a {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.odoc-toc li ul {
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.odoc-toc ul {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.odoc-toc ul li {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.odoc-toc>ul>li {
|
||||||
|
margin-bottom: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.odoc-toc ul li li {
|
||||||
|
border-left: 1px solid var(--toc-list-border);
|
||||||
|
margin-left: 5px;
|
||||||
|
padding-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile adjustements. */
|
||||||
|
|
||||||
|
@media only screen and (max-width: 95ex) {
|
||||||
|
.odoc-content {
|
||||||
|
margin: auto;
|
||||||
|
padding: 2em;
|
||||||
|
}
|
||||||
|
.odoc-toc {
|
||||||
|
position: static;
|
||||||
|
width: auto;
|
||||||
|
min-width: unset;
|
||||||
|
max-width: unset;
|
||||||
|
border: none;
|
||||||
|
padding: 0.2em 1em;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print adjustements. */
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
body {
|
||||||
|
color: black;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
body nav:first-child {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Syntax highlighting (based on github-gist) */
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
display: block;
|
||||||
|
background: var(--code-background);
|
||||||
|
padding: 0.5em;
|
||||||
|
color: var(--color);
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-meta {
|
||||||
|
color: #969896;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-template-variable,
|
||||||
|
.hljs-strong,
|
||||||
|
.hljs-emphasis,
|
||||||
|
.hljs-quote {
|
||||||
|
color: #df5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-selector-tag {
|
||||||
|
color: #a71d5d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-type,
|
||||||
|
.hljs-class .hljs-title {
|
||||||
|
color: #458;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-symbol,
|
||||||
|
.hljs-bullet,
|
||||||
|
.hljs-attribute {
|
||||||
|
color: #0086b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-section,
|
||||||
|
.hljs-name {
|
||||||
|
color: #63a35c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-tag {
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-attr,
|
||||||
|
.hljs-selector-id,
|
||||||
|
.hljs-selector-class,
|
||||||
|
.hljs-selector-attr,
|
||||||
|
.hljs-selector-pseudo {
|
||||||
|
color: #795da3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-addition {
|
||||||
|
color: #55a532;
|
||||||
|
background-color: #eaffea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-deletion {
|
||||||
|
color: #bd2c00;
|
||||||
|
background-color: #ffecec;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-link {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------
|
||||||
|
Copyright (c) 2016 The odoc contributors
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
---------------------------------------------------------------------------*/
|
BIN
one.png
BIN
one.png
Binary file not shown.
Before Width: | Height: | Size: 223 KiB |
6
src/dune
6
src/dune
|
@ -1,6 +0,0 @@
|
||||||
(library
|
|
||||||
(name mirage_monitoring)
|
|
||||||
(public_name mirage-monitoring)
|
|
||||||
(wrapped false)
|
|
||||||
(libraries logs metrics metrics-lwt metrics-influx mirage-time mirage-clock
|
|
||||||
memtrace-mirage tcpip mirage-runtime))
|
|
|
@ -1,275 +0,0 @@
|
||||||
open Lwt.Infix
|
|
||||||
|
|
||||||
let src = Logs.Src.create "mirage-monitoring" ~doc:"MirageOS monitoring"
|
|
||||||
module Log = (val Logs.src_log src : Logs.LOG)
|
|
||||||
|
|
||||||
let ( let* ) = Result.bind
|
|
||||||
|
|
||||||
let create ~f =
|
|
||||||
let data : (string, int) Hashtbl.t = Hashtbl.create 7 in
|
|
||||||
(fun x ->
|
|
||||||
let key = f x in
|
|
||||||
let cur = match Hashtbl.find_opt data key with
|
|
||||||
| None -> 0
|
|
||||||
| Some x -> x
|
|
||||||
in
|
|
||||||
Hashtbl.replace data key (succ cur)),
|
|
||||||
(fun () ->
|
|
||||||
let data, total =
|
|
||||||
Hashtbl.fold (fun key value (acc, total) ->
|
|
||||||
(Metrics.uint key value :: acc), value + total)
|
|
||||||
data ([], 0)
|
|
||||||
in
|
|
||||||
Metrics.uint "total" total :: data)
|
|
||||||
|
|
||||||
let counter_metrics ~f name =
|
|
||||||
let open Metrics in
|
|
||||||
let doc = "Counter metrics" in
|
|
||||||
let incr, get = create ~f in
|
|
||||||
let data thing = incr thing; Data.v (get ()) in
|
|
||||||
Src.v ~doc ~tags:Metrics.Tags.[] ~data name
|
|
||||||
|
|
||||||
let vmname = Metrics.field ~doc:"name of the virtual machine" "vm" Metrics.String
|
|
||||||
|
|
||||||
let get_log_levels s =
|
|
||||||
let qs = String.split_on_char ',' s in
|
|
||||||
let srcs = Logs.Src.list () in
|
|
||||||
let srcs = List.map (fun src -> Logs.Src.name src, Logs.Src.level src) srcs in
|
|
||||||
let* srcs =
|
|
||||||
match qs with
|
|
||||||
| [""] ->
|
|
||||||
let all_level = Logs.level () in
|
|
||||||
Ok (("*", all_level) :: List.filter (fun (_,l) -> l <> all_level) srcs)
|
|
||||||
| ["*"] ->
|
|
||||||
let all_level = Logs.level () in
|
|
||||||
Ok (("*", all_level) :: srcs)
|
|
||||||
| qs ->
|
|
||||||
let* () =
|
|
||||||
let src_names = List.map fst srcs in
|
|
||||||
match List.find_opt (fun src -> not (List.mem src src_names)) qs with
|
|
||||||
| Some bad_src -> Error ("unknown source: " ^ bad_src)
|
|
||||||
| None -> Ok ()
|
|
||||||
in
|
|
||||||
Ok (List.filter (fun (name, _) -> List.mem name qs) srcs)
|
|
||||||
in
|
|
||||||
let levels =
|
|
||||||
List.map (fun (name, level) ->
|
|
||||||
name ^ ":" ^ Logs.level_to_string level)
|
|
||||||
srcs
|
|
||||||
in
|
|
||||||
Ok (`String (String.concat "," levels))
|
|
||||||
|
|
||||||
let get_metrics s =
|
|
||||||
let qs = String.split_on_char ',' s in
|
|
||||||
let srcs = Metrics.Src.list () in
|
|
||||||
let srcs =
|
|
||||||
List.map (fun src ->
|
|
||||||
Metrics.Src.name src, Metrics.Src.is_active src)
|
|
||||||
srcs
|
|
||||||
in
|
|
||||||
let* srcs =
|
|
||||||
match qs with
|
|
||||||
| [""] ->
|
|
||||||
let all = Metrics.all_enabled () in
|
|
||||||
Ok (("*", all) :: (List.filter (fun (_, b) -> b <> all) srcs))
|
|
||||||
| ["*"] ->
|
|
||||||
let all = Metrics.all_enabled () in
|
|
||||||
let tags = Metrics.tags_enabled () in
|
|
||||||
Ok (("*", all) :: List.map (fun t -> "tag:" ^ t, true) tags @ srcs)
|
|
||||||
| qs ->
|
|
||||||
let* () =
|
|
||||||
let src_names = List.map fst srcs in
|
|
||||||
match List.find_opt (fun src -> not (List.mem src src_names)) qs with
|
|
||||||
| Some bad_src -> Error ("unknown source: " ^ bad_src)
|
|
||||||
| None -> Ok ()
|
|
||||||
in
|
|
||||||
Ok (List.filter (fun (n, _) -> List.mem n qs) srcs)
|
|
||||||
in
|
|
||||||
let metrics =
|
|
||||||
List.map (fun (name, act) ->
|
|
||||||
name ^ ":" ^ if act then "enabled" else "disabled")
|
|
||||||
srcs
|
|
||||||
in
|
|
||||||
Ok (`String (String.concat "," metrics))
|
|
||||||
|
|
||||||
let adjust_log_level s =
|
|
||||||
let ts =
|
|
||||||
List.map
|
|
||||||
(fun s -> (fst Mirage_runtime.Conv.log_threshold) s)
|
|
||||||
(String.split_on_char ',' s)
|
|
||||||
in
|
|
||||||
let* oks =
|
|
||||||
List.fold_left (fun acc t ->
|
|
||||||
let* acc = acc in
|
|
||||||
match t with
|
|
||||||
| `Ok l -> Ok (l :: acc)
|
|
||||||
| `Error msg -> Error msg)
|
|
||||||
(Ok []) ts
|
|
||||||
in
|
|
||||||
Mirage_runtime.set_level ~default:(Logs.level ()) oks;
|
|
||||||
Ok `Empty
|
|
||||||
|
|
||||||
let enable_of_str s =
|
|
||||||
let s = String.lowercase_ascii s in
|
|
||||||
if s = "enable" || s = "on" then
|
|
||||||
Ok `Enable
|
|
||||||
else if s = "disable" || s = "off" then
|
|
||||||
Ok `Disable
|
|
||||||
else
|
|
||||||
Error ("couldn't decode 'enable' or 'disable': " ^ s)
|
|
||||||
|
|
||||||
let adjust_metrics s =
|
|
||||||
let ts =
|
|
||||||
List.map (fun s ->
|
|
||||||
match String.split_on_char ':' s with
|
|
||||||
| [ en ] | [ "*" ; en ] ->
|
|
||||||
let* en_or_d = enable_of_str en in
|
|
||||||
Ok (`All, en_or_d)
|
|
||||||
| [ src ; en ] ->
|
|
||||||
let* en_or_d = enable_of_str en in
|
|
||||||
Ok (`Src src, en_or_d)
|
|
||||||
| [ "src" ; src ; en ] ->
|
|
||||||
let* en_or_d = enable_of_str en in
|
|
||||||
Ok (`Src src, en_or_d)
|
|
||||||
| [ "tag" ; tag ; en ] ->
|
|
||||||
let* en_or_d = enable_of_str en in
|
|
||||||
Ok (`Tag tag, en_or_d)
|
|
||||||
| _ -> Error ("couldn't decode metrics " ^ s))
|
|
||||||
(String.split_on_char ',' s)
|
|
||||||
in
|
|
||||||
let* (all, srcs, tags) =
|
|
||||||
List.fold_left (fun acc t ->
|
|
||||||
let* (all, srcs, tags) = acc in
|
|
||||||
let* t = t in
|
|
||||||
match t with
|
|
||||||
| `All, en_or_d -> Ok (Some en_or_d, srcs, tags)
|
|
||||||
| `Src s, en_or_d -> Ok (all, (s, en_or_d) :: srcs, tags)
|
|
||||||
| `Tag t, en_or_d -> Ok (all, srcs, (t, en_or_d) :: tags))
|
|
||||||
(Ok (None, [], [])) ts
|
|
||||||
in
|
|
||||||
(match all with
|
|
||||||
| Some `Enable -> Metrics.enable_all ()
|
|
||||||
| Some `Disable -> Metrics.disable_all ()
|
|
||||||
| None -> ());
|
|
||||||
List.iter (fun (tag, e_or_d) ->
|
|
||||||
match e_or_d with
|
|
||||||
| `Enable -> Metrics.enable_tag tag
|
|
||||||
| `Disable -> Metrics.disable_tag tag)
|
|
||||||
tags ;
|
|
||||||
List.iter (fun (src, e_or_d) ->
|
|
||||||
match List.find_opt (fun s -> Metrics.Src.name s = src) (Metrics.Src.list ()), e_or_d with
|
|
||||||
| Some src, `Enable -> Metrics.Src.enable src
|
|
||||||
| Some src, `Disable -> Metrics.Src.disable src
|
|
||||||
| None, _ ->
|
|
||||||
Log.warn (fun m -> m "%s is not a valid metrics source." src))
|
|
||||||
srcs ;
|
|
||||||
Ok `Empty
|
|
||||||
|
|
||||||
module Make (T : Mirage_time.S) (P : Mirage_clock.PCLOCK) (S : Tcpip.Stack.V4V6) = struct
|
|
||||||
module Memtrace = Memtrace.Make(P)(S.TCP)
|
|
||||||
|
|
||||||
let timer conn get host stack dst =
|
|
||||||
let datas =
|
|
||||||
Metrics.SM.fold (fun src (tags, data) acc ->
|
|
||||||
let name = Metrics.Src.name src in
|
|
||||||
Metrics_influx.encode_line_protocol (host@tags) data name :: acc)
|
|
||||||
(get ()) []
|
|
||||||
in
|
|
||||||
let datas = String.concat "" datas in
|
|
||||||
let write flow =
|
|
||||||
Log.debug (fun m -> m "sending measurements");
|
|
||||||
S.TCP.write flow (Cstruct.of_string datas) >|= function
|
|
||||||
| Ok () -> ()
|
|
||||||
| Error e ->
|
|
||||||
Log.err (fun m -> m "error %a writing to metrics" S.TCP.pp_write_error e);
|
|
||||||
conn := None
|
|
||||||
in
|
|
||||||
match !conn with
|
|
||||||
| None ->
|
|
||||||
begin
|
|
||||||
Log.debug (fun m -> m "creating connection");
|
|
||||||
S.TCP.create_connection (S.tcp stack) dst >>= function
|
|
||||||
| Error msg ->
|
|
||||||
Log.err (fun m -> m "couldn't create connection %a"
|
|
||||||
S.TCP.pp_error msg);
|
|
||||||
Lwt.return_unit
|
|
||||||
| Ok flow ->
|
|
||||||
conn := Some flow;
|
|
||||||
write flow
|
|
||||||
end
|
|
||||||
| Some f -> write f
|
|
||||||
|
|
||||||
let timer_loop get host interval stack dst () =
|
|
||||||
let conn = ref None in
|
|
||||||
let rec one () =
|
|
||||||
Lwt.join [
|
|
||||||
timer conn get host stack dst;
|
|
||||||
T.sleep_ns (Duration.of_sec interval)
|
|
||||||
] >>= fun () ->
|
|
||||||
(one[@tailcall]) ()
|
|
||||||
in
|
|
||||||
one ()
|
|
||||||
|
|
||||||
let create_listener stack port =
|
|
||||||
S.TCP.listen (S.tcp stack) ~port (fun f ->
|
|
||||||
(S.TCP.read f >>= function
|
|
||||||
| Ok `Data data ->
|
|
||||||
if Cstruct.length data > 0 then
|
|
||||||
let rest = Cstruct.(to_string (shift data 1)) in
|
|
||||||
let r =
|
|
||||||
match Cstruct.get_char data 0 with
|
|
||||||
| 'L' -> adjust_log_level rest
|
|
||||||
| 'M' -> adjust_metrics rest
|
|
||||||
| 'l' -> get_log_levels rest
|
|
||||||
| 'm' -> get_metrics rest
|
|
||||||
| _ -> Error "unknown command"
|
|
||||||
in
|
|
||||||
let msg =
|
|
||||||
match r with
|
|
||||||
| Ok `Empty -> "ok"
|
|
||||||
| Ok `String reply -> "ok: " ^ reply
|
|
||||||
| Error msg -> "error: " ^ msg
|
|
||||||
in
|
|
||||||
S.TCP.write f (Cstruct.of_string msg) >|= function
|
|
||||||
| Ok () -> ()
|
|
||||||
| Error e ->
|
|
||||||
Log.warn (fun m -> m "write error on log & metrics listener %a"
|
|
||||||
S.TCP.pp_write_error e)
|
|
||||||
else
|
|
||||||
(Log.debug (fun m -> m "received empty data on log & metrics listener");
|
|
||||||
Lwt.return_unit)
|
|
||||||
| Ok `Eof ->
|
|
||||||
Log.debug (fun m -> m "EOF on log & metrics listener");
|
|
||||||
Lwt.return_unit
|
|
||||||
| Error e ->
|
|
||||||
Log.debug (fun m -> m "read error on log & metrics listener %a"
|
|
||||||
S.TCP.pp_error e);
|
|
||||||
Lwt.return_unit) >>= fun () ->
|
|
||||||
S.TCP.close f)
|
|
||||||
|
|
||||||
let create ?(interval = 10) ?hostname dst ?(port = 8094) ?(listen_port = 2323)
|
|
||||||
?(memtrace_port = 4242) ?(sampling_rate = 1e-4) stack =
|
|
||||||
S.TCP.listen (S.tcp stack) ~port:memtrace_port
|
|
||||||
(fun f ->
|
|
||||||
(* only allow a single tracing client *)
|
|
||||||
match Memtrace.Memprof_tracer.active_tracer () with
|
|
||||||
| Some _ ->
|
|
||||||
Log.warn (fun m -> m "memtrace tracing already active");
|
|
||||||
S.TCP.close f
|
|
||||||
| None ->
|
|
||||||
Logs.info (fun m -> m "starting memtrace tracing");
|
|
||||||
let tracer = Memtrace.start_tracing ~context:None ~sampling_rate f in
|
|
||||||
Lwt.async (fun () ->
|
|
||||||
S.TCP.read f >|= fun _ ->
|
|
||||||
Logs.info (fun m -> m "memtrace tracing read returned, closing");
|
|
||||||
Memtrace.stop_tracing tracer);
|
|
||||||
Lwt.return_unit);
|
|
||||||
let get_cache, reporter = Metrics.cache_reporter () in
|
|
||||||
Metrics.set_reporter reporter;
|
|
||||||
Metrics.enable_all ();
|
|
||||||
Metrics_lwt.init_periodic (fun () -> T.sleep_ns (Duration.of_sec interval));
|
|
||||||
let host = match hostname with None -> [] | Some host -> [vmname host] in
|
|
||||||
Lwt.async (timer_loop get_cache host interval stack (dst, port));
|
|
||||||
create_listener stack listen_port
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
|
|
||||||
val counter_metrics : f:('a -> string) -> string ->
|
|
||||||
(Metrics.field list, 'a -> Metrics.data) Metrics.src
|
|
||||||
|
|
||||||
val vmname : string -> Metrics.field
|
|
||||||
(** [vmname name] creates a [tag] with the virtual machine name. *)
|
|
||||||
|
|
||||||
module Make (T : Mirage_time.S) (P : Mirage_clock.PCLOCK) (S : Tcpip.Stack.V4V6) : sig
|
|
||||||
|
|
||||||
val create : ?interval:int -> ?hostname:string -> Ipaddr.t -> ?port:int ->
|
|
||||||
?listen_port:int -> ?memtrace_port:int -> ?sampling_rate:float -> S.t ->
|
|
||||||
unit
|
|
||||||
(** [create ~interval ~hostname ip ~port ~listen_port ~memtrace_port ~sampling_rate stack]
|
|
||||||
initiates monitoring on [stack] for the unikernel. The metrics are reported
|
|
||||||
every [interval] (defaults to 10) seconds to [ip] on [port] (defaults to
|
|
||||||
8094) via TCP using the influxd wire protocol. On [listen_port] (defaults
|
|
||||||
to 2323) a TCP connection can be initiated to adjust the log level and
|
|
||||||
enable and disable metrics sources. On [memtrace_port] (defaults to 4242)
|
|
||||||
a single TCP client can connect simultaneously to receive a [Gc.Memprof]
|
|
||||||
trace. The [sampling_rate] defaults to [1e-4]. *)
|
|
||||||
end
|
|
Loading…
Reference in a new issue