-
Notifications
You must be signed in to change notification settings - Fork 488
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add documentation for metrics endpoint (#816)
Co-authored-by: André Colomb <[email protected]>
- Loading branch information
Showing
9 changed files
with
359 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
_build/ | ||
_deployed | ||
_deployed.old | ||
_syncthing |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
// Copyright (C) 2023 The Syncthing Authors. | ||
// | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
// You can obtain one at https://mozilla.org/MPL/2.0/. | ||
|
||
// Usage: go run script/find-metrics.go > metrics.md | ||
// | ||
// This script finds all of the metrics in the Syncthing codebase and prints | ||
// them in Markdown format. It's used to generate the metrics documentation | ||
// for the Syncthing docs. | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"go/ast" | ||
"go/token" | ||
"log" | ||
"os" | ||
"strconv" | ||
"strings" | ||
|
||
"golang.org/x/exp/slices" | ||
"golang.org/x/tools/go/packages" | ||
) | ||
|
||
type metric struct { | ||
subsystem string | ||
name string | ||
help string | ||
kind string | ||
} | ||
|
||
func main() { | ||
flag.Parse() | ||
if flag.NArg() != 1 { | ||
fmt.Println("Usage: find-metrics <path>") | ||
os.Exit(1) | ||
} | ||
|
||
opts := &packages.Config{ | ||
Dir: flag.Arg(0), | ||
Mode: packages.NeedSyntax | packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedImports | packages.NeedDeps, | ||
} | ||
|
||
pkgs, err := packages.Load(opts, "github.com/syncthing/syncthing/...") | ||
if err != nil { | ||
log.Fatalln(err) | ||
} | ||
|
||
var coll metricCollector | ||
for _, pkg := range pkgs { | ||
for _, file := range pkg.Syntax { | ||
ast.Inspect(file, coll.Visit) | ||
} | ||
} | ||
coll.print() | ||
} | ||
|
||
type metricCollector struct { | ||
metrics []metric | ||
} | ||
|
||
func (c *metricCollector) Visit(n ast.Node) bool { | ||
if gen, ok := n.(*ast.GenDecl); ok { | ||
// We're only interested in var declarations (var metricWhatever = | ||
// promauto.NewCounter(...) etc). | ||
if gen.Tok != token.VAR { | ||
return false | ||
} | ||
|
||
for _, spec := range gen.Specs { | ||
// We want to look at the value given to a var (the NewCounter() | ||
// etc call). | ||
if vsp, ok := spec.(*ast.ValueSpec); ok { | ||
// There should be only one value. | ||
if len(vsp.Values) != 1 { | ||
continue | ||
} | ||
|
||
// The value should be a function call. | ||
call, ok := vsp.Values[0].(*ast.CallExpr) | ||
if !ok { | ||
continue | ||
} | ||
|
||
// The call should be a selector expression | ||
// (package.Identifer). | ||
sel, ok := call.Fun.(*ast.SelectorExpr) | ||
if !ok { | ||
continue | ||
} | ||
|
||
// The package selector should be `promauto`. | ||
selID, ok := sel.X.(*ast.Ident) | ||
if !ok || selID.Name != "promauto" { | ||
continue | ||
} | ||
|
||
// The function should be one of the New* functions. | ||
var kind string | ||
switch sel.Sel.Name { | ||
case "NewCounter": | ||
kind = "counter" | ||
case "NewGauge": | ||
kind = "gauge" | ||
case "NewCounterVec": | ||
kind = "counter vector" | ||
case "NewGaugeVec": | ||
kind = "gauge vector" | ||
default: | ||
continue | ||
} | ||
|
||
// The arguments to the function should be a single | ||
// composite (struct literal). Grab all of the fields in the | ||
// declaration into a map so we can easily access them. | ||
args := make(map[string]string) | ||
for _, el := range call.Args[0].(*ast.CompositeLit).Elts { | ||
kv := el.(*ast.KeyValueExpr) | ||
key := kv.Key.(*ast.Ident).Name // e.g., "Name" | ||
val := kv.Value.(*ast.BasicLit).Value // e.g., `"foo"` | ||
args[key], _ = strconv.Unquote(val) | ||
} | ||
|
||
// Build the full name of the metric from the namespace + | ||
// subsystem + name, like Prometheus does. | ||
var parts []string | ||
if v := args["Namespace"]; v != "" { | ||
parts = append(parts, v) | ||
} | ||
if v := args["Subsystem"]; v != "" { | ||
parts = append(parts, v) | ||
} | ||
if v := args["Name"]; v != "" { | ||
parts = append(parts, v) | ||
} | ||
fullName := strings.Join(parts, "_") | ||
|
||
// Add the metric to the list. | ||
c.metrics = append(c.metrics, metric{ | ||
subsystem: args["Subsystem"], | ||
name: fullName, | ||
help: args["Help"], | ||
kind: kind, | ||
}) | ||
} | ||
} | ||
} | ||
return true | ||
} | ||
|
||
func (c *metricCollector) print() { | ||
slices.SortFunc(c.metrics, func(a, b metric) int { | ||
if a.subsystem != b.subsystem { | ||
return strings.Compare(a.subsystem, b.subsystem) | ||
} | ||
return strings.Compare(a.name, b.name) | ||
}) | ||
|
||
var prevSubsystem string | ||
for _, m := range c.metrics { | ||
if m.subsystem != prevSubsystem { | ||
fmt.Println(header(fmt.Sprintf("Package *%s*", m.subsystem), "~")) | ||
prevSubsystem = m.subsystem | ||
} | ||
fmt.Println(header(fmt.Sprintf("Metric *%v* (%s)", m.name, m.kind), "^")) | ||
fmt.Println(wordwrap(sentenceize(m.help), 72)) | ||
fmt.Println() | ||
} | ||
} | ||
|
||
func header(header, underline string) string { | ||
under := strings.Repeat(underline, len(header)) | ||
return fmt.Sprintf("%s\n%s\n", header, under) | ||
} | ||
|
||
func sentenceize(s string) string { | ||
if s == "" { | ||
return "" | ||
} | ||
if !strings.HasSuffix(s, ".") { | ||
return s + "." | ||
} | ||
return s | ||
} | ||
|
||
func wordwrap(s string, width int) string { | ||
var lines []string | ||
for _, line := range strings.Split(s, "\n") { | ||
for len(line) > width { | ||
i := strings.LastIndex(line[:width], " ") | ||
if i == -1 { | ||
i = width | ||
} | ||
lines = append(lines, line[:i]) | ||
line = line[i+1:] | ||
} | ||
lines = append(lines, line) | ||
} | ||
return strings.Join(lines, "\n") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
Package *events* | ||
~~~~~~~~~~~~~~~~ | ||
|
||
Metric *syncthing_events_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total number of created/forwarded/dropped events. | ||
|
||
Package *fs* | ||
~~~~~~~~~~~~ | ||
|
||
Metric *syncthing_fs_operation_bytes_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total number of filesystem bytes transferred, per filesystem root and | ||
operation. | ||
|
||
Metric *syncthing_fs_operation_seconds_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total time spent in filesystem operations, per filesystem root and | ||
operation. | ||
|
||
Metric *syncthing_fs_operations_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total number of filesystem operations, per filesystem root and | ||
operation. | ||
|
||
Package *model* | ||
~~~~~~~~~~~~~~~ | ||
|
||
Metric *syncthing_model_folder_processed_bytes_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total amount of data processed during folder syncing, per folder ID and | ||
data source (network/local_origin/local_other/local_shifted/skipped). | ||
|
||
Metric *syncthing_model_folder_pull_seconds_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total time spent in folder pull iterations, per folder ID. | ||
|
||
Metric *syncthing_model_folder_pulls_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total number of folder pull iterations, per folder ID. | ||
|
||
Metric *syncthing_model_folder_scan_seconds_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total time spent in folder scan iterations, per folder ID. | ||
|
||
Metric *syncthing_model_folder_scans_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total number of folder scan iterations, per folder ID. | ||
|
||
Metric *syncthing_model_folder_state* (gauge vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Current folder state. | ||
|
||
Metric *syncthing_model_folder_summary* (gauge vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Current folder summary data (counts for global/local/need | ||
files/directories/symlinks/deleted/bytes). | ||
|
||
Package *protocol* | ||
~~~~~~~~~~~~~~~~~~ | ||
|
||
Metric *syncthing_protocol_recv_bytes_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total amount of data received, per device. | ||
|
||
Metric *syncthing_protocol_recv_decompressed_bytes_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total amount of data received, after decompression, per device. | ||
|
||
Metric *syncthing_protocol_recv_messages_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total number of messages received, per device. | ||
|
||
Metric *syncthing_protocol_sent_bytes_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total amount of data sent, per device. | ||
|
||
Metric *syncthing_protocol_sent_messages_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total number of messages sent, per device. | ||
|
||
Metric *syncthing_protocol_sent_uncompressed_bytes_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total amount of data sent, before compression, per device. | ||
|
||
Package *scanner* | ||
~~~~~~~~~~~~~~~~~ | ||
|
||
Metric *syncthing_scanner_hashed_bytes_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total amount of data hashed, per folder. | ||
|
||
Metric *syncthing_scanner_scanned_items_total* (counter vector) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Total number of items (files/directories) inspected, per folder. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#!/bin/sh | ||
set -euo pipefail | ||
|
||
rm -rf _syncthing | ||
git clone --depth 1 https://github.com/syncthing/syncthing.git _syncthing | ||
pushd _script | ||
go run ./find-metrics ../_syncthing > ../includes/metrics-list.rst | ||
popd |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ Usage | |
guilisten | ||
ldap | ||
tuning | ||
metrics | ||
|
||
syncing | ||
untrusted | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
Prometheus-Style Metrics | ||
======================== | ||
|
||
Syncthing provides an endpoint for Prometheus-style metrics. Metrics are | ||
served on the ``/metrics`` path on the GUI / API address. The metrics endpoint | ||
requires authentication when the GUI / API is configured to require | ||
authentication; see :doc:`/dev/rest` for details. | ||
|
||
Metrics | ||
------- | ||
|
||
The following metrics are available. | ||
|
||
.. include:: ../includes/metrics-list.rst |