feat(server/metrics): add documentation around the new metrics endpoint

This commit is contained in:
perf3ct 2025-05-26 13:51:03 -07:00
parent 3479f5016d
commit ab2f27180d
7 changed files with 287 additions and 202 deletions

File diff suppressed because one or more lines are too long

View File

@ -275,9 +275,9 @@
content via the injected <code>now</code> and <code>parentNote</code> variables.</p>
<p>Examples:</p>
<ul>
<li><code>${parentNote.getLabel('authorName')}'s literary works</code>
<li><code><span class="math-tex">\({parentNote.getLabel('authorName')}'s literary works</span></code>
</li>
<li><code>Log for ${now.format('YYYY-MM-DD HH:mm:ss')}</code>
<li><code>Log for \){now.format('YYYY-MM-DD HH:mm:ss')}</code>
</li>
<li>to mirror the parent's template.</li>
</ul>

View File

@ -0,0 +1,88 @@
<p>&nbsp;</p>
<h1><strong>Trilium Metrics API</strong></h1>
<p>The Trilium metrics API provides comprehensive monitoring data about your
Trilium instance, designed for external monitoring systems like Prometheus.</p>
<h2><strong>Endpoint</strong></h2>
<ul>
<li><strong>URL</strong>: <code>/etapi/metrics</code>
</li>
<li><strong>Method</strong>: <code>GET</code>
</li>
<li><strong>Authentication</strong>: ETAPI token required</li>
<li><strong>Default Format</strong>: Prometheus text format</li>
</ul>
<h2><strong>Authentication</strong></h2>
<p>You need an ETAPI token to access the metrics endpoint. Get one by:</p><pre><code class="language-text-x-trilium-auto"># Get an ETAPI token
curl -X POST http://localhost:8080/etapi/auth/login \
-H "Content-Type: application/json" \
-d '{"password": "your_password"}'
</code></pre>
<h2><strong>Usage</strong></h2>
<h3><strong>Prometheus Format (Default)</strong></h3><pre><code class="language-text-x-trilium-auto">curl -H "Authorization: YOUR_ETAPI_TOKEN" \
http://localhost:8080/etapi/metrics
</code></pre>
<p>Returns metrics in Prometheus text format:</p><pre><code class="language-text-x-trilium-auto"># HELP trilium_info Trilium instance information
# TYPE trilium_info gauge
trilium_info{version="0.91.6",db_version="231",node_version="v18.17.0"} 1 1701432000
# HELP trilium_notes_total Total number of notes including deleted
# TYPE trilium_notes_total gauge
trilium_notes_total 1234 1701432000
</code></pre>
<h3><strong>JSON Format</strong></h3><pre><code class="language-text-x-trilium-auto">curl -H "Authorization: YOUR_ETAPI_TOKEN" \
"http://localhost:8080/etapi/metrics?format=json"
</code></pre>
<p>Returns detailed metrics in JSON format for debugging or custom integrations.</p>
<h2><strong>Available Metrics</strong></h2>
<h3><strong>Instance Information</strong></h3>
<ul>
<li><code>trilium_info</code> - Version and build information with labels</li>
</ul>
<h3><strong>Database Metrics</strong></h3>
<ul>
<li><code>trilium_notes_total</code> - Total notes (including deleted)</li>
<li><code>trilium_notes_deleted</code> - Number of deleted notes</li>
<li><code>trilium_notes_active</code> - Number of active notes</li>
<li><code>trilium_notes_protected</code> - Number of protected notes</li>
<li><code>trilium_attachments_total</code> - Total attachments</li>
<li><code>trilium_attachments_active</code> - Active attachments</li>
<li><code>trilium_revisions_total</code> - Total note revisions</li>
<li><code>trilium_branches_total</code> - Active branches</li>
<li><code>trilium_attributes_total</code> - Active attributes</li>
<li><code>trilium_blobs_total</code> - Total blob records</li>
<li><code>trilium_etapi_tokens_total</code> - Active ETAPI tokens</li>
<li><code>trilium_embeddings_total</code> - Note embeddings (if available)</li>
</ul>
<h3><strong>Categorized Metrics</strong></h3>
<ul>
<li><code>trilium_notes_by_type{type="text|code|image|file"}</code> - Notes
by type</li>
<li><code>trilium_attachments_by_type{mime_type="..."}</code> - Attachments
by MIME type</li>
</ul>
<h3><strong>Statistics</strong></h3>
<ul>
<li><code>trilium_database_size_bytes</code> - Database size in bytes</li>
<li><code>trilium_oldest_note_timestamp</code> - Timestamp of oldest note</li>
<li><code>trilium_newest_note_timestamp</code> - Timestamp of newest note</li>
<li><code>trilium_last_modified_timestamp</code> - Last modification timestamp</li>
</ul>
<h2><strong>Prometheus Configuration</strong></h2>
<p>Add to your <code>prometheus.yml</code>:</p><pre><code class="language-text-x-trilium-auto">scrape_configs:
- job_name: 'trilium'
static_configs:
- targets: ['localhost:8080']
metrics_path: '/etapi/metrics'
headers:
Authorization: 'YOUR_ETAPI_TOKEN'
scrape_interval: 30s
</code></pre>
<h2><strong>Error Responses</strong></h2>
<ul>
<li><code>400</code> - Invalid format parameter</li>
<li><code>401</code> - Missing or invalid ETAPI token</li>
<li><code>500</code> - Internal server error</li>
</ul>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>

View File

@ -1735,37 +1735,30 @@
{
"type": "relation",
"name": "internalLink",
"value": "_optionsAppearance",
"value": "nRhnJkTT8cPs",
"isInheritable": false,
"position": 180
},
{
"type": "relation",
"name": "internalLink",
"value": "nRhnJkTT8cPs",
"value": "KSZ04uQ2D1St",
"isInheritable": false,
"position": 190
},
{
"type": "relation",
"name": "internalLink",
"value": "KSZ04uQ2D1St",
"value": "WOcw2SLH6tbX",
"isInheritable": false,
"position": 200
},
{
"type": "relation",
"name": "internalLink",
"value": "WOcw2SLH6tbX",
"isInheritable": false,
"position": 210
},
{
"type": "relation",
"name": "internalLink",
"value": "veGu4faJErEM",
"isInheritable": false,
"position": 220
"position": 210
},
{
"type": "label",
@ -2053,30 +2046,23 @@
{
"type": "relation",
"name": "internalLink",
"value": "_options",
"value": "oPVyFC7WL2Lp",
"isInheritable": false,
"position": 30
},
{
"type": "relation",
"name": "internalLink",
"value": "oPVyFC7WL2Lp",
"value": "3seOhtN8uLIY",
"isInheritable": false,
"position": 40
},
{
"type": "relation",
"name": "internalLink",
"value": "3seOhtN8uLIY",
"isInheritable": false,
"position": 50
},
{
"type": "relation",
"name": "internalLink",
"value": "cbkrhQjrkKrh",
"isInheritable": false,
"position": 60
"position": 50
},
{
"type": "label",
@ -3076,65 +3062,51 @@
{
"type": "relation",
"name": "internalLink",
"value": "_optionsTextNotes",
"value": "zEY4DaJG4YT5",
"isInheritable": false,
"position": 10
},
{
"type": "relation",
"name": "internalLink",
"value": "_optionsCodeNotes",
"value": "iPIMuisry3hd",
"isInheritable": false,
"position": 20
},
{
"type": "relation",
"name": "internalLink",
"value": "zEY4DaJG4YT5",
"value": "6f9hih2hXXZk",
"isInheritable": false,
"position": 30
},
{
"type": "relation",
"name": "internalLink",
"value": "iPIMuisry3hd",
"value": "4TIF1oA4VQRO",
"isInheritable": false,
"position": 40
},
{
"type": "relation",
"name": "internalLink",
"value": "6f9hih2hXXZk",
"value": "BlN9DFI679QC",
"isInheritable": false,
"position": 50
},
{
"type": "relation",
"name": "internalLink",
"value": "4TIF1oA4VQRO",
"value": "XpOYSgsLkTJy",
"isInheritable": false,
"position": 60
},
{
"type": "relation",
"name": "internalLink",
"value": "BlN9DFI679QC",
"isInheritable": false,
"position": 70
},
{
"type": "relation",
"name": "internalLink",
"value": "XpOYSgsLkTJy",
"isInheritable": false,
"position": 80
},
{
"type": "relation",
"name": "internalLink",
"value": "s1aBHPd79XYj",
"isInheritable": false,
"position": 90
"position": 70
},
{
"type": "label",
@ -5479,19 +5451,12 @@
"isInheritable": false,
"position": 10
},
{
"type": "relation",
"name": "internalLink",
"value": "_optionsTextNotes",
"isInheritable": false,
"position": 20
},
{
"type": "relation",
"name": "internalLink",
"value": "BlN9DFI679QC",
"isInheritable": false,
"position": 30
"position": 20
},
{
"type": "label",
@ -5668,23 +5633,16 @@
{
"type": "relation",
"name": "internalLink",
"value": "_optionsTextNotes",
"value": "zEY4DaJG4YT5",
"isInheritable": false,
"position": 30
},
{
"type": "relation",
"name": "internalLink",
"value": "zEY4DaJG4YT5",
"isInheritable": false,
"position": 40
},
{
"type": "relation",
"name": "internalLink",
"value": "BFvAtE74rbP6",
"isInheritable": false,
"position": 50
"position": 40
},
{
"type": "label",
@ -6694,19 +6652,12 @@
"isInheritable": false,
"position": 20
},
{
"type": "relation",
"name": "internalLink",
"value": "_optionsTextNotes",
"isInheritable": false,
"position": 30
},
{
"type": "relation",
"name": "internalLink",
"value": "zEY4DaJG4YT5",
"isInheritable": false,
"position": 40
"position": 30
},
{
"type": "label",
@ -8521,191 +8472,184 @@
{
"type": "relation",
"name": "internalLink",
"value": "_help_YKWqdJhzi2VY",
"value": "OFXdgB2nNk1F",
"isInheritable": false,
"position": 50
},
{
"type": "relation",
"name": "internalLink",
"value": "OFXdgB2nNk1F",
"value": "BlN9DFI679QC",
"isInheritable": false,
"position": 60
},
{
"type": "relation",
"name": "internalLink",
"value": "BlN9DFI679QC",
"value": "vZWERwf8U3nx",
"isInheritable": false,
"position": 70
},
{
"type": "relation",
"name": "internalLink",
"value": "vZWERwf8U3nx",
"value": "oPVyFC7WL2Lp",
"isInheritable": false,
"position": 80
},
{
"type": "relation",
"name": "internalLink",
"value": "oPVyFC7WL2Lp",
"value": "GPERMystNGTB",
"isInheritable": false,
"position": 90
},
{
"type": "relation",
"name": "internalLink",
"value": "GPERMystNGTB",
"value": "CoFPLs3dRlXc",
"isInheritable": false,
"position": 100
},
{
"type": "relation",
"name": "internalLink",
"value": "CoFPLs3dRlXc",
"value": "AlhDUqhENtH7",
"isInheritable": false,
"position": 110
},
{
"type": "relation",
"name": "internalLink",
"value": "AlhDUqhENtH7",
"value": "pKK96zzmvBGf",
"isInheritable": false,
"position": 120
},
{
"type": "relation",
"name": "internalLink",
"value": "pKK96zzmvBGf",
"value": "WFGzWeUK6arS",
"isInheritable": false,
"position": 130
},
{
"type": "relation",
"name": "internalLink",
"value": "WFGzWeUK6arS",
"value": "0ESUbbAxVnoK",
"isInheritable": false,
"position": 140
},
{
"type": "relation",
"name": "internalLink",
"value": "0ESUbbAxVnoK",
"value": "J5Ex1ZrMbyJ6",
"isInheritable": false,
"position": 150
},
{
"type": "relation",
"name": "internalLink",
"value": "J5Ex1ZrMbyJ6",
"value": "d3fAXQ2diepH",
"isInheritable": false,
"position": 160
},
{
"type": "relation",
"name": "internalLink",
"value": "d3fAXQ2diepH",
"value": "MgibgPcfeuGz",
"isInheritable": false,
"position": 170
},
{
"type": "relation",
"name": "internalLink",
"value": "MgibgPcfeuGz",
"value": "m523cpzocqaD",
"isInheritable": false,
"position": 180
},
{
"type": "relation",
"name": "internalLink",
"value": "m523cpzocqaD",
"value": "9sRHySam5fXb",
"isInheritable": false,
"position": 190
},
{
"type": "relation",
"name": "internalLink",
"value": "9sRHySam5fXb",
"value": "u3YFHC9tQlpm",
"isInheritable": false,
"position": 200
},
{
"type": "relation",
"name": "internalLink",
"value": "u3YFHC9tQlpm",
"value": "R9pX4DGra2Vt",
"isInheritable": false,
"position": 210
},
{
"type": "relation",
"name": "internalLink",
"value": "R9pX4DGra2Vt",
"value": "iRwzGnHPzonm",
"isInheritable": false,
"position": 220
},
{
"type": "relation",
"name": "internalLink",
"value": "iRwzGnHPzonm",
"value": "BCkXAVs63Ttv",
"isInheritable": false,
"position": 230
},
{
"type": "relation",
"name": "internalLink",
"value": "BCkXAVs63Ttv",
"value": "47ZrP6FNuoG8",
"isInheritable": false,
"position": 240
},
{
"type": "relation",
"name": "internalLink",
"value": "47ZrP6FNuoG8",
"value": "KC1HB96bqqHX",
"isInheritable": false,
"position": 250
},
{
"type": "relation",
"name": "internalLink",
"value": "KC1HB96bqqHX",
"value": "BFvAtE74rbP6",
"isInheritable": false,
"position": 260
},
{
"type": "relation",
"name": "internalLink",
"value": "BFvAtE74rbP6",
"value": "bdUJEHsAPYQR",
"isInheritable": false,
"position": 270
},
{
"type": "relation",
"name": "internalLink",
"value": "bdUJEHsAPYQR",
"value": "AxshuNRegLAv",
"isInheritable": false,
"position": 280
},
{
"type": "relation",
"name": "internalLink",
"value": "AxshuNRegLAv",
"value": "81SGnPGMk7Xc",
"isInheritable": false,
"position": 290
},
{
"type": "relation",
"name": "internalLink",
"value": "81SGnPGMk7Xc",
"isInheritable": false,
"position": 300
},
{
"type": "relation",
"name": "internalLink",
"value": "xWbu3jpNWapp",
"isInheritable": false,
"position": 310
"position": 300
},
{
"type": "label",
@ -10639,177 +10583,93 @@
{
"type": "relation",
"name": "internalLink",
"value": "_globalNoteMap",
"value": "YKWqdJhzi2VY",
"isInheritable": false,
"position": 40
},
{
"type": "relation",
"name": "internalLink",
"value": "_sqlConsole",
"value": "ivYnonVFBxbQ",
"isInheritable": false,
"position": 50
},
{
"type": "relation",
"name": "internalLink",
"value": "YKWqdJhzi2VY",
"value": "eIg8jdvaoNNd",
"isInheritable": false,
"position": 60
},
{
"type": "relation",
"name": "internalLink",
"value": "_search",
"value": "QEAPj01N5f7w",
"isInheritable": false,
"position": 70
},
{
"type": "relation",
"name": "internalLink",
"value": "_bulkAction",
"value": "m1lbrzyKDaRB",
"isInheritable": false,
"position": 80
},
{
"type": "relation",
"name": "internalLink",
"value": "ivYnonVFBxbQ",
"value": "x3i7MxGccDuM",
"isInheritable": false,
"position": 90
},
{
"type": "relation",
"name": "internalLink",
"value": "_backendLog",
"value": "bdUJEHsAPYQR",
"isInheritable": false,
"position": 100
},
{
"type": "relation",
"name": "internalLink",
"value": "_userHidden",
"value": "xYmIYSP6wE3F",
"isInheritable": false,
"position": 110
},
{
"type": "relation",
"name": "internalLink",
"value": "_lbTplRoot",
"value": "u3YFHC9tQlpm",
"isInheritable": false,
"position": 120
},
{
"type": "relation",
"name": "internalLink",
"value": "_share",
"value": "qzNzp9LYQyPT",
"isInheritable": false,
"position": 130
},
{
"type": "relation",
"name": "internalLink",
"value": "_lbRoot",
"value": "CdNpE2pqjmI6",
"isInheritable": false,
"position": 140
},
{
"type": "relation",
"name": "internalLink",
"value": "_options",
"value": "R9pX4DGra2Vt",
"isInheritable": false,
"position": 150
},
{
"type": "relation",
"name": "internalLink",
"value": "_lbMobileRoot",
"isInheritable": false,
"position": 160
},
{
"type": "relation",
"name": "internalLink",
"value": "_help",
"isInheritable": false,
"position": 170
},
{
"type": "relation",
"name": "internalLink",
"value": "eIg8jdvaoNNd",
"isInheritable": false,
"position": 180
},
{
"type": "relation",
"name": "internalLink",
"value": "QEAPj01N5f7w",
"isInheritable": false,
"position": 190
},
{
"type": "relation",
"name": "internalLink",
"value": "m1lbrzyKDaRB",
"isInheritable": false,
"position": 200
},
{
"type": "relation",
"name": "internalLink",
"value": "x3i7MxGccDuM",
"isInheritable": false,
"position": 210
},
{
"type": "relation",
"name": "internalLink",
"value": "bdUJEHsAPYQR",
"isInheritable": false,
"position": 220
},
{
"type": "relation",
"name": "internalLink",
"value": "xYmIYSP6wE3F",
"isInheritable": false,
"position": 230
},
{
"type": "relation",
"name": "internalLink",
"value": "u3YFHC9tQlpm",
"isInheritable": false,
"position": 240
},
{
"type": "relation",
"name": "internalLink",
"value": "qzNzp9LYQyPT",
"isInheritable": false,
"position": 250
},
{
"type": "relation",
"name": "internalLink",
"value": "CdNpE2pqjmI6",
"isInheritable": false,
"position": 260
},
{
"type": "relation",
"name": "internalLink",
"value": "R9pX4DGra2Vt",
"isInheritable": false,
"position": 270
},
{
"type": "relation",
"name": "internalLink",
"value": "4TIF1oA4VQRO",
"isInheritable": false,
"position": 280
"position": 160
},
{
"type": "label",
@ -10831,6 +10691,33 @@
"dataFileName": "Hidden Notes_image.png"
}
]
},
{
"isClone": false,
"noteId": "uYF7pmepw27K",
"notePath": [
"pOsGYCXsbNQG",
"tC7s2alapj8V",
"uYF7pmepw27K"
],
"title": "Metrics",
"notePosition": 240,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [
{
"type": "label",
"name": "iconClass",
"value": "bx bxs-data",
"isInheritable": false,
"position": 10
}
],
"format": "markdown",
"dataFileName": "Metrics.md",
"attachments": []
}
]
},

File diff suppressed because one or more lines are too long

View File

@ -27,4 +27,4 @@ The code will:
1. First load the `config.ini` file as before
2. Then scan all environment variables for ones starting with `TRILIUM_`
3. Parse these variables into section/key pairs
4. Merge them with the config from the file, with environment variables taking precedence
4. Merge them with the config from the file, with environment variables taking precedence

View File

@ -0,0 +1,110 @@
# **Trilium Metrics API**
The Trilium metrics API provides comprehensive monitoring data about your Trilium instance, designed for external monitoring systems like Prometheus.
## **Endpoint**
* **URL**: `/etapi/metrics`
* **Method**: `GET`
* **Authentication**: ETAPI token required
* **Default Format**: Prometheus text format
## **Authentication**
You need an ETAPI token to access the metrics endpoint. Get one by:
```
# Get an ETAPI token
curl -X POST http://localhost:8080/etapi/auth/login \
-H "Content-Type: application/json" \
-d '{"password": "your_password"}'
```
## **Usage**
### **Prometheus Format (Default)**
```
curl -H "Authorization: YOUR_ETAPI_TOKEN" \
http://localhost:8080/etapi/metrics
```
Returns metrics in Prometheus text format:
```
# HELP trilium_info Trilium instance information
# TYPE trilium_info gauge
trilium_info{version="0.91.6",db_version="231",node_version="v18.17.0"} 1 1701432000
# HELP trilium_notes_total Total number of notes including deleted
# TYPE trilium_notes_total gauge
trilium_notes_total 1234 1701432000
```
### **JSON Format**
```
curl -H "Authorization: YOUR_ETAPI_TOKEN" \
"http://localhost:8080/etapi/metrics?format=json"
```
Returns detailed metrics in JSON format for debugging or custom integrations.
## **Available Metrics**
### **Instance Information**
* `trilium_info` - Version and build information with labels
### **Database Metrics**
* `trilium_notes_total` - Total notes (including deleted)
* `trilium_notes_deleted` - Number of deleted notes
* `trilium_notes_active` - Number of active notes
* `trilium_notes_protected` - Number of protected notes
* `trilium_attachments_total` - Total attachments
* `trilium_attachments_active` - Active attachments
* `trilium_revisions_total` - Total note revisions
* `trilium_branches_total` - Active branches
* `trilium_attributes_total` - Active attributes
* `trilium_blobs_total` - Total blob records
* `trilium_etapi_tokens_total` - Active ETAPI tokens
* `trilium_embeddings_total` - Note embeddings (if available)
### **Categorized Metrics**
* `trilium_notes_by_type{type="text|code|image|file"}` - Notes by type
* `trilium_attachments_by_type{mime_type="..."}` - Attachments by MIME type
### **Statistics**
* `trilium_database_size_bytes` - Database size in bytes
* `trilium_oldest_note_timestamp` - Timestamp of oldest note
* `trilium_newest_note_timestamp` - Timestamp of newest note
* `trilium_last_modified_timestamp` - Last modification timestamp
## **Prometheus Configuration**
Add to your `prometheus.yml`:
```
scrape_configs:
- job_name: 'trilium'
static_configs:
- targets: ['localhost:8080']
metrics_path: '/etapi/metrics'
headers:
Authorization: 'YOUR_ETAPI_TOKEN'
scrape_interval: 30s
```
## **Error Responses**
* `400` - Invalid format parameter
* `401` - Missing or invalid ETAPI token
* `500` - Internal server error