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
View file

@ -1,4 +0,0 @@
_build/
.merlin
*.install
.*.swp

View file

@ -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

View file

@ -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/).

View file

@ -1,2 +0,0 @@
(lang dune 1.0)
(name mirage-monitoring)

2
highlight.pack.js Normal file

File diff suppressed because one or more lines are too long

19
index.html Normal file
View 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>

View file

@ -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.
"""

View 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> &#x00BB; <a href="../index.html">Mirage_monitoring</a> &#x00BB; 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">&#45;&gt;</span></span>
<span>?quick:bool <span class="arrow">&#45;&gt;</span></span>
<span>?hostname:string <span class="arrow">&#45;&gt;</span></span>
<span><span class="xref-unresolved">Ipaddr</span>.t <span class="arrow">&#45;&gt;</span></span>
<span>?port:int <span class="arrow">&#45;&gt;</span></span>
<span>?listen_port:int <span class="arrow">&#45;&gt;</span></span>
<span>?memtrace_port:int <span class="arrow">&#45;&gt;</span></span>
<span>?sampling_rate:float <span class="arrow">&#45;&gt;</span></span>
<span><span class="xref-unresolved">S</span>.t <span class="arrow">&#45;&gt;</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>

View 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> &#x00BB; 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">&#45;&gt;</span></span> string )</span> <span class="arrow">&#45;&gt;</span></span>
<span>string <span class="arrow">&#45;&gt;</span></span>
<span><span>( <span><span class="xref-unresolved">Metrics</span>.field list</span>, <span><span class="type-var">'a</span> <span class="arrow">&#45;&gt;</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">&#45;&gt;</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>

View 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
View 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

View file

@ -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))

View file

@ -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

View file

@ -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